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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。