失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > Node爬虫之使用 async 控制并发

Node爬虫之使用 async 控制并发

时间:2021-06-10 06:42:36

相关推荐

Node爬虫之使用 async 控制并发

上文 《Node爬虫之使用 eventproxy 控制并发》我们说到用 node 爬了csdn首页数据,但是这些请求完全是并发的,如果某些网站有 “反爬” 机制,就很有可能封锁你的 IP。这样的情况下我们就可以使用 async 模块。主要用到的是 async 的mapLimit(arr, limit, iterator, callback)接口。

async.mapLimit(arr, 5, function (url, callback) {fetchUrl(url, callback);}, function (err, result) {res.send(result);});

第一个参数 arr为数组,保存了需要爬取页面的 url,第二个参数 limit 表示并发爬取数量。第三个参数是迭代函数(每个 url 需要执行这个函数),其第一个参数 url,是 urls 数组的每个 item,第二个参数 callback 与 mapLimit 方法第四个参数有关,callback 会往 result 参数里存放数据。如何理解?callback 是第三个参数 iterator 的回调,以爬虫为例,爬完页面肯定会分析一些数据,然后保存,执行 callback 函数就能把结果保存在 result(第四个参数函数中的参数) 中。

首先,我们采集 需要爬取页面的 url,保存在 urls 数组中:

$('.clearfix .list_con .title h2 a').each(function(idx, element) {var $element = $(element);// console.log('$element',$element);var href = url.resolve(csdn, $element.attr('href'));urls.push(href);});

接着我们用 async 进行异步爬取:

async.mapLimit(urls, 5, function(url, callback) {fetchUrl(url, callback);},function(err, result) {console.log('final: ', result);response.send(result);})

通过fetchUrl函数来抓起页面内容:

var fetchUrl = function(url, callback) {superagent.get(url).end(function(err, res) {if(err) {console.log(err);}console.log('fetch ' + url + ' successful!');var $ = cheerio.load(res.text);var jsonData = {title: $('.title-article').text().trim(),href: url,comment1: $('.comment').eq(0).text().trim() };console.log(JSON.stringify(jsonData));callback(null, jsonData);})}

这里要注意的是 callback 中的第二个参数,其实 jsonData 已经储存在了 mapLimit 方法第四个参数的 result 参数中。

完整代码:

var express = require('express');var superagent = require('superagent');var cheerio = require('cheerio');var async = require('async');var url = require('url');var csdn = '/';var app = express();app.get('/', function(request, response, next) {superagent.get(csdn).end(function(err, res) {if(err) {return console.error(err);}var urls = [];var $ = cheerio.load(res.text);$('.clearfix .list_con .title h2 a').each(function(idx, element) {var $element = $(element);// console.log('$element',$element);var href = url.resolve(csdn, $element.attr('href'));urls.push(href);});console.log('urls', urls);var concurrencyCount = 0;var fetchUrl = function(url, callback) {superagent.get(url).end(function(err, res) {if(err) {console.log(err);}console.log('fetch ' + url + ' successful!');var $ = cheerio.load(res.text);var jsonData = {title: $('.title-article').text().trim(),href: url,comment1: $('.comment').eq(0).text().trim() };console.log(JSON.stringify(jsonData));callback(null, jsonData);})}async.mapLimit(urls, 5, function(url, callback) {fetchUrl(url, callback);},function(err, result) {console.log('final: ', result);response.send(result);})})})app.listen(3002, function() {console.log('app is listenling at port 3002');})

结果:

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

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

参考:使用 async 控制并发

如果觉得《Node爬虫之使用 async 控制并发》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。