Node.js真正的异步并发( async 控制并发)

2015年02月28日 javascript 暂无评论 阅读 175 views 次

上节课的代码并不完美。为什么这么说,是因为在 lesson4 中,我们一次性发了10 个并发请求出去,要知道,许多网站有可能会因为你发出的并发连接数太多而当你是在恶意请求,把你的 IP 封掉。

我们在写爬虫的时候,如果有 1000 个链接要去爬,那么不可能同时发出 1000 个并发链接出去对不对?我们需要控制一下并发的数量,比如并发5个就好,然后慢慢抓完这 1000 个链接。

用 async 来做这件事很简单。

这次我们要介绍的是 async 的 mapLimit(arr, limit, iterator, callback) 接口。另外,还有个常用的控制并发连接数的接口是 queue(worker, concurrency),大家可以去 https://github.com/caolan/async#queueworker-concurrency 看看说明。

这回我就不带大家爬网站了,我们来专注知识点:并发连接数控制。

对了,还有个问题是,什么时候用 eventproxy,什么时候使用 async 呢?它们不都是用来做异步流程控制的吗?

我的答案是:

当你需要去多个源(一般是小于 10 个)汇总数据的时候,用 eventproxy 方便;当你需要用到队列,需要控制并发数,或者你喜欢函数式编程思维时,使用 async。大部分场景是前者,所以我个人大部分时间是用 eventproxy 的。

正题开始。

var async = require('async');
var superagent = require('superagent');
var cheerio = require('cheerio');
var url = require('url');
var cnodeUrl = 'http://www.daliane.com/?order=views';

 

// 并发连接数的计数器

var concurrencyCount = 0;
var fetchUrl = function (url, callback) {

 // delay 的值在 2000 以内,是个随机的整数

var delay = parseInt((Math.random() * 10000000) % 2000, 10);
concurrencyCount++;
console.log('现在的并发数是', concurrencyCount, ',正在抓取的是', url, ',耗时' + delay + '毫秒');
setTimeout(function () {
concurrencyCount--;
callback(null, url + ' html content');
}, delay);
};
superagent.get(cnodeUrl)
.end(function (err, res) {
if (err) {
return console.error(err);
}
var topicUrls = [];
var $ = cheerio.load(res.text);
$('section.content h1.entry-title a').each(function (idx, element) {

var $element = $(element);

topicUrls.push($element.attr('href'));
});
async.mapLimit(topicUrls, 2, function (url, callback) {
fetchUrl(url, callback);
}, function (err, result) {
console.log('final:');
console.log(result);
});

});

 

将网站的链接传入后,一个一个的抓取。

可以看到,一开始,并发链接数是从 1 开始增长的,增长到 2时,就不再增加。当其中有任务完成时,再继续抓取。并发连接数始终控制在2 个

效果图:

6

 

给我留言

您必须 登录 才能发表留言!

Copyright © 大一网 保留所有权利.  

用户登录

分享到: