异步队列控制爬虫
发布于 7 年前 作者 houbean 3173 次浏览 来自 分享

异步控制我一直想不出太好的办法,github上有一些优秀的异步流程控制库,从点赞数量上及可以看出来很优秀,本着爱吓折腾的情怀就自己写了一个异步流程控制的模块,用起来还相当清爽,之前发过一个 用异步队列控制你的异步,后来改了又改,终于改成想要的样子了。

安装

npm install queue5

使用

const queue = require('queue5');
const arr = [];
for (let i = 0; i < 100; i += 1) {
  arr.push(1000 + i);
}

async function test(args) {
  const result = await queue(args, 20, (item, next) => {
    setTimeout(() => {
      next('next');      // 通过next()传递数据
    }, item);
  });
  console.log(result);
}

test(arr);

结果

2017-06-06-01.png

实战

决定用这个异步队列控制一个爬虫试试,相对于python写的爬虫简直不要太清爽,首先安装爬虫所需要的工具:

npm install queue5 request cheerio

然后就是开始爬取网页了,简单的拿博客园试下手,希望大家都不要用博客园试手,可以换个网站尝试下,假设我现在有个需求,需要爬取博客园前50页的文章的标题,所以可以这样:

const queue = require('queue5');
const cheerio = require('cheerio');
const request = require('request');

const urls = [];
for (let i = 0; i < 50; i++) {
  urls.push('https://www.cnblogs.com/#p' + i);
}
// 用到了async函数,请自觉升级node至7.0以上
async function main (args){
  // 这里控制五个并发,不要给博客园太大压力
  const titles = await queue(args, 5, function(url, next){
    request(url, function(err, res, body){
      if (!err) {
        const $ = cheerio.load(body);
        let title =  $('a.titlelnk').toArray().map(function(item){
          return $(item).text();
        })
        next(title);  //通过next()将数据进行传递
      }
    });
  });
  // titles中是很多标题数组组成的一个数组,有兴趣的同学可以打印出来自己看一下
  // 所以需要对titles中的数据进行处理,我希望得到一个标题组成的数组,所以就简单处理了下
  let result = [];
  titles.forEach(function(item){
    result = result.concat(item);
  });
  console.log(result);
}

main(urls);

其中用到了async和await的相关知识,有不明白这部分内容的同学可以自行百度下,目前队列中对数据用next()进行传递,最终得到的结果是一个数组,由于案例中的title是一个数组,所以最终得到的结果是一个数组组成的数组,这个处理起来也很方便,看具体需求。 花了很长时间写了这么个异步队列,终于得到差不多想要的效果了。

最后

一如既往:欢迎Star和Issues https://github.com/houbean/queue5 也欢迎有疑惑或者建议的同学在评论区发表评论,我会尽力解答的。

2 回复

async/await 的目的就是屏蔽回调,看到两者一块出现感觉怪怪的 控制并发可以使用promise.all 楼主的队列是用数组表示的,这就很尴尬了, 如果数组小的话用promise.all就能解决,数组大的话…我爬pixiv有几千万个异步 所以我一般使用redis做队列 以上仅为个人看法

@Yuki-Minakami受教了,确实没考虑到你说的场景;只是简单的实现了下对并发数量的精确控制,单就异步任务的并发控制来说比promise.all来说还是有点优势,不过局限性肯定也是有的,比如队列用数组表示,不过当个小工具使使还是可以的。谢谢你的意见。

回到顶部