最近在用node js编写爬虫的过程中,遇到了一个奇怪的问题,爬虫代码正常执行,但总是中途停止,不再继续执行,也不报错退出,而且发生的时间也很随机,很头疼,
开始分析是爆栈,然而检查代码,,发现基于event loop 的node js到处都是回调,很难爆栈。分析是内存占用过多卡死?定时执行gc,也没有用,,最后终于发现,,竟然是因为请求时未设置超时时间,,导致回调无法执行,,无法进行下一步。
然而node js http模块不支持设置超时时间,只能伪实现一个,话不多说,上代码,,用到了http模块,cheerio模块(用于将爬取到的网页变为类jq访问的文档树),iconv-lite(用于改变网页数据编码,这里有个坑,http.get默认会把网页编码设置为utf-8,如果爬取网页是gbk的,就会乱码),
const http = require("http");
const fs = require("fs");
const cheerio = require("cheerio");
const iconv = require('iconv-lite');
var req = null
request_timer = setTimeout(function () { //这里通过定时器伪实现超时设置,20秒没有相应,结束请求,执行回调,重点
req.abort();
console.log('Request Timeout.');
}, 20000);
req = http.get(url, res => {
if (res) {
clearTimeout(request_timer); //如果请求有反应,无论成功失败,清楚定时器
console.log("准备获取数据")
var data = [];
res.on("data", data1 => {// 因为数据分块传输,监听数据块拼接,
console.log("数据获取中")
data.push(data1)
})
res.on("end", data2 => {
var res = iconv.decode(Buffer.concat(data), 'gb2312');//通过iconv改变王爷编码,这里根据网页meta标签中设置的编码而设置,如果不设置默认为utf-8,,
var $ = cheerio.load(res);//这里是把获取的网页数据转化为类dom树
console.log("处理完毕")
var text = $('').eq(1).text(); //这里是通过类jq的方式获取网页中想要的数据
})
}
})
req.on("error", function () { //这里记得要监听错误事件,否则请求出错就会结束进程
console.log("错误暂停")
})
网友评论