node crawler如何添加promise支持
背景
最近在组内做一些爬虫相关的工作,本来想自己简单造个轮子的,但是经网友推荐后,采用了node-crawler,用了一段时间过后,确实满足了我的绝大部分需求,但是其api却不支持promise,而且我还需要一些同步爬取、同步处理的能力,如果不用promise的话,写法很不优雅,所以我就简单地给其封装了一层promiseapi
现状
目前node-crawler的使用方式不支持promise,这里直接给出npm上的使用例子
constCrawler=require("crawler") //实例化 constc=newCrawler({ //...可以传入一些配置 callback:function(error,res,done){ //请求回调,实例化的时候传入的callback是作为默认callback的,后续每次抓取如果没有传入callback,那么都会调用默认callback done(); } }) //爬取 c.queue([{ uri:'http://parishackers.org/', jQuery:false, //Theglobalcallbackwon'tbecalled callback:function(error,res,done){ if(error){ console.log(error); }else{ console.log('Grabbed',res.body.length,'bytes'); } done(); } }])
这样的回调方式对于多爬虫同步爬取很不友好
改造
理想使用方式:
constCrawler=require('crawler') constc=newCrawler({ //一些默认配置 }) c .queue({ uri:'xxx' }) .then(res=>{ //抓取成功 }) .catch(err=>{ //抓取失败 })
改造方案:
//utils/crawler.js constCrawler=require('crawler') constdefaultOptions={ jQuery:false, rateLimit:fetchRateLimit, retries:0, timeout:fetchTimeout, } module.exports=classPromiseifyCrawlerextendsCrawler{ //namespace是为了后续抓取结果统一上报时候进行区分 constructor(namespace='unknow',options={}){ if(typeofnamespace==='object'){ options=namespace namespace='unknow' } options=merge({},defaultOptions,options) constcb=options.callback options.callback=(err,res,done)=>{ typeofcb==='function'&&cb(err,res,noop) process.nextTick(done) //在这里可以自定义抓取成功还是失败 //我这里直接设置的是如果httpcode不是200就视为错误 //而且在这里也可以做一些抓取成功失败的统计 if(err||res.statusCode!==200){ if(!err)err=newError(`${res.statusCode}-${res.statusMessage}`) err.options=res.options err.options.npolisReject(err) }else{ res.options.npolisResolve(res) } } options.headers=Object.assign({},options.headers,{ 'X-Requested-With':'XMLHttpRequest', }) super(options) } queue(options={}){ //每次抓取都是一个新的promise returnnewPromise((resolve,reject)=>{ //然后在options里挂载上resolve和reject //这样在全局callback上就可以用到了 options.npolisResolve=resolve options.npolisReject=reject constpr=options.preRequest options.preRequest=(options,done)=>{ typeofpr==='function'&&pr(options,noop) //在这里也可以做一些通用的抓取前的处理 done() } super.queue(options) }) } //directapi同理 } //使用 constCrawler=require('./utils/crawler') constcrawler=newCrawler('示例爬虫namespace') crawler .queue({ uri:'xxx', preRequest:options=>log('开始抓取'), }) .then(res=>{ log('爬取成功') returnres }) .catch(err=>{ log('爬取失败') throwerr }) promise化后,多个爬取任务同步爬取写法就友好多了: //抓取任务1 constfetchTask1=()=>crawler.queue({/*配置*/}).then(res=>handle(res)) //抓取任务2 constfetchTask2=()=>crawler.queue({/*配置*/}).then(res=>handle(res)) constfetch=()=>{ returnPromise.all([ fetchTask1(), fetchTask2(), ]) } fetch()
这样就完成了对node-crawler的promise化改造了
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。