通常咱们在写爬虫的时候,不少网站会由于你并发请求数太多当作是在恶意请求,封掉你的IP,为了防止这种状况的发生,咱们通常会在代码里控制并发请求数,Node里面通常借助async模块来实现。javascript
mapLimit(arr, limit, iterator, callback)java
arr中通常是多个请求的url,limit为并发限制次数,mapLimit方法将arr中的每一项依次拿给iterator去执行,执行结果传给最后的callback;node
下面是以前写过的一个简单的爬虫示例,将爬取到的新闻标题和路径保存在一个Excel表格中,限制并发数为3,代码以下git
webSpider.js:github
//request调用url主函数 (mapLimit iterator) function main(option, callback) { n++; timeline[option] = new Date().getTime(); console.log('如今的并发数是', n, ',正在抓取的是', option); request(option, function(err, res, body) { if(!err && res.statusCode == 200){ var $ = cheerio.load(body); $('#post_list .post_item').each(function(index, element) { // console.log(element); var item = [$(element).find('.post_item_body h3 a').text(),$(element).find('.post_item_body h3 a').attr('href')]; dataArr[0].data.push(item); }); console.log('抓取', option, '结束,耗时:', new Date().getTime()-timeline[option], '毫秒'); n--; callback(null, 'done!'); }else{ console.log(err); n--; callback(err, null); } }); } //限制请求并发数为3 async.mapLimit(options, 3, main.bind(this), function(err, result){ if(err) { console.log(err); } else { fs.writeFile('data/cnbNews.xlsx', xlsx.build(dataArr), 'utf-8', function(err){ if(err){ console.log('write file error!'); }else{ console.log('write file success!'); } }); } });
这里迭代器里面第二个参数callback(即请求每一条url完成以后的回调方法)是关键,没有异常的状况下全部options中的url都请求完成以后会回调mapLimit方法的回调方法进行后续操做(如这里的生成文件),若是单条url请求异常,回调方法中会接收到err并报出错误,不能执行后续生成文件的操做。web
async.mapLimit(options, 3, function(option, callback) { request(option, main); callback(null); }, function(err, result) { if(err) { console.log(err); } else { console.log('done!'); } });
如上,网上有些资料中是在迭代器中request方法执行完成以后调用callback,由于request方法异步接收请求数据,这种写法会使async.mapLimit
方法limit参数无效,致使没法达到限制请求并发数的目的,这里须要注意下。并发
执行webSpider.js,异步
node webSpider.js
执行结果能够看到并发数依次增长,增长到3时再也不继续增长,等待前面一条请求执行完成后才会请求下一条,这样的话,若是咱们须要爬取1000条数据,就能够并发10条请求,慢慢爬完这1000个连接,这样就不用担忧因并发太多被封IP这种状况发生了。完整代码已上传GitHub,有兴趣去试试吧!async