[译]Node Crawler:强大的Node开源爬虫

自从Node横空出世后,很快有人就用它来开发爬虫,网上也常见Node爬虫教程。然而,很难看到一个通用的、功能丰富的爬虫开源项目,到Github上找了一下找到这个,算是目前能找到的最好的了。

这里将它的文档翻译一下,期待更多的实用案例。

node-crawler

目标打造成Node社区最强大和流行的爬虫/内容抽取工具库,且支持生产环境。

特性:

  • 服务端DOM和自动jQuery注入,使用Cheerio(默认)或JSDOM
  • 可配置的连接池大小和重试次数
  • Control rate limit
  • 支持设置请求队列优先级
  • forceUTF8模式可让爬虫处理字符集编码探测和转换
  • 兼容Node 4.x及以上版本

更新日志:https://github.com/bda-research/node-crawler/blob/master/CHANGELOG.md

上手指南

安装

$ npm install crawler

使用

var Crawler = require("crawler");

var c = new Crawler({
    maxConnections : 10,
    // 这个回调每个爬取到的页面都会触发
    callback : function (error, res, done) {
        if(error){
            console.log(error);
        }else{
            var $ = res.$;
            // $默认使用Cheerio
            // 这是为服务端设计的轻量级jQuery核心实现
            console.log($("title").text());
        }
        done();
    }
});

// 爬取一个URL,使用默认的callback
c.queue('http://www.amazon.com');

// 爬取URL列表
c.queue(['http://www.google.com/','http://www.yahoo.com']);

// 爬取页面,自定义callback和参数
c.queue([{
    uri: 'http://parishackers.org/',
    jQuery: false,

    // 覆盖全局的callback
    callback: function (error, res, done) {
        if(error){
            console.log(error);
        }else{
            console.log('Grabbed', res.body.length, 'bytes');
        }
        done();
    }
}]);

// 在队列中加入一些HTML代码,无需爬取(mostly for tests)
c.queue([{
    html: '<p>This is a <strong>test</strong></p>'
}]);

控制爬取间隔时间

当你在流量网站时,使用 rateLimit 控制间隔时间。

var crawler = require("crawler");

var c = new Crawler({
    rateLimit: 1000, // `maxConnections` 会强制为1个
    callback: function(err, res, done){
        console.log(res.$("title").text());
        done();
    }
});

c.queue(tasks);//在两次任务间最小时间间隔为 1000 (ms)

配置项指南

你可以将这些配置发给 Crawler() 构造器,让它们成为全局配置,或者自定义 queue() 的请求已覆盖全局配置。

这个配置列表在mikeal的request项目配置的基础上做了扩展,并且会直接发送给 request() 方法。

基本请求配置项:

回调:

  • callback(error, res, done): 请求完成后会被调用
    • error: Error
    • res: http.IncomingMessage 请求的回应,包括 $options
      • res.statusCode: Number HTTP status code. E.G.200
      • res.body: Buffer | String HTTP返回内容,可能是HTML页面、纯文本或XML文档。
      • res.headers: Object HTTP请求的返回头
      • res.request: Request Mikeal的 Request 的实例,以取代 http.ClientRequest
        • res.request.uri: urlObject 解析后的URL实体
        • res.request.method: String HTTP request method. E.G. GET
        • res.request.headers: Object HTTP request headers
      • res.options: Options 配置项
      • $: jQuery Selector HTML和XML的选择器
    • done: Function 回调中要做的事情做完后需要调用这个

计划任务选项:

  • maxConnections: Number 连接池大小 (默认 10).
  • rateLimit: Number 每条请求之间的间隔时间,单位毫秒 (默认 0).
  • priorityRange: Number 可接受的优先级数值,最小为0 (默认 10).
  • priority: Number 当前请求的优先级 (默认 5).

重试选项:

  • retries: Number 请求失败后的重试次数 (默认 3),
  • retryTimeout: Number 重试前等待的时间,单位毫秒 (默认 10000),

服务端DOM配置:

  • jQuery: Boolean|String|Object 如果设置为true,使用cheerio和默认配置来注入爬取内容。或使用解析选项自定义cheerio. 当返回false时停止注入jQuery选择器。如果在你的项目中存在内存泄漏,使用一个替代的解析器"whacko"来避免。(默认 true)

字符集编码:

  • forceUTF8: Boolean 如果设置为true,爬虫将从HTTP请求头中获取字符集或从HTML中获取meta tag,并且将它转换到UTF8,不用再担心编码问题了(默认 true)
  • incomingEncoding: String 当设置 forceUTF8: true 时可自行设置接收内容的编码 (默认 null),爬虫就不用自己检测编码了。 如, incomingEncoding : 'windows-1255'. 查看 所有支持的编码

缓存:

  • skipDuplicates: Boolean 设置为true时,跳过已爬取过的URI,甚至不触发 callback()(默认 false)。 不推荐改动,更好的做法是在爬虫之外使用seenreq进行处理。

其它:

  • rotateUA: Boolean 当为true时, userAgent 应该是数组,并进行轮换 (默认 false)
  • userAgent: String|Array, 如果 rotateUA 为 false, 但 userAgent 是一个数组, 爬虫将使用第一个值。
  • referer: String 当为真时设置HTTP的 referer header

Class:Crawler

Event: 'schedule'

当一个任务被加到计划时触发.

crawler.on('schedule',function(options){
    options.proxy = "http://proxy:port";
});

Event: 'limiterChange'

当limiter改变时触发.

Event: 'request'

当爬虫准备好发送请求时触发.

如果你想在发出请求之前的最后阶段改变配置,可以监听这个事件。

crawler.on('request',function(options){
    options.qs.timestamp = new Date().getTime();
});

Event: 'drain'

当队列为空时触发。

crawler.on('drain',function(){
    // 执行一些操作,如,释放数据库连接。
    db.end(); // 关闭MySQL连接。
});

crawler.queue(uri|options)

将任务加入队列并等待执行。

crawler.queueSize

  • Number

队列数量,该属性为只读。

处理瓶颈

使用limiter控制爬取频率。所有提交到limiter的任务都需要遵守rateLimitmaxConnections 的限制。rateLimit是两个任务之间的最小间隔,maxConnections是最大的并发数。limiters之间是互相独立的。一个通常的用例是为不同的代理设置不同的limiter。另外值得一提的是,当rateLimit设置为非0的值时,maxConnections 的值将被强制为1.

var crawler = require('crawler');

var c = new Crawler({
    rateLimit: 2000,
    maxConnections: 1,
    callback: function(error, res, done) {
        if(error) {
            console.log(error)
        } else {
            var $ = res.$;
            console.log($('title').text())
        }
        done();
    }
})

// 如果你想以2000毫秒的间隔执行任务
c.queue('http://www.somewebsite.com/page/1')
c.queue('http://www.somewebsite.com/page/2')
c.queue('http://www.somewebsite.com/page/3')

// 如果你想为设置代理,并为每个代理设置2000毫秒的间隔
c.queue({
    uri:'http://www.somewebsite.com/page/1',
    limiter:'proxy_1',
    proxy:'proxy_1'
})
c.queue({
    uri:'http://www.somewebsite.com/page/2',
    limiter:'proxy_2',
    proxy:'proxy_2'
})
c.queue({
    uri:'http://www.somewebsite.com/page/3',
    limiter:'proxy_3',
    proxy:'proxy_3'
})
c.queue({
    uri:'http://www.somewebsite.com/page/4',
    limiter:'proxy_1',
    proxy:'proxy_1'
})

Work with Cheerio or JSDOM

爬虫默认使用Cheerio,并将JSDOM作为可选的替代。JSDOM更稳定,如果你想使用JSDOM,你需要引入该依赖require('jsdom'),并配置爬虫。

Working with Cheerio

jQuery: true //(default)
//OR
jQuery: 'cheerio'
//OR
jQuery: {
    name: 'cheerio',
    options: {
        normalizeWhitespace: true,
        xmlMode: true
    }
}

这些解析配置从htmlparser2里继承而来。你可以使用所有可用的配置。默认的配置为:

{
    normalizeWhitespace: false,
    xmlMode: false,
    decodeEntities: true
}

需要所有的配置项和它们的效果,查看 这里 以及
htmlparser2的配置项来源

Work with JSDOM

要使用JSDOM,你需要先在项目目录下npm install jsdom,然后配置爬虫。

var jsdom = require('jsdom');
var Crawler = require('crawler');

var c = new Crawler({
    jQuery: jsdom
});

如何测试

安装并运行Httpbin

爬虫使用本地的httpbin来测试。你可以从PyPI安装httpbin并将其作为WSGI应用来允许。比如,使用Gunicorn:

$ pip install httpbin
# launch httpbin as a daemon with 6 worker on localhost
$ gunicorn httpbin:app -b 127.0.0.1:8000 -w 6 --daemon
# Finally
$ npm install && npm test

使用Docker

在安装 Docker 之后, 你可以执行:

# Builds the local test environment
$ docker build -t node-crawler .

# Runs tests
$ docker run node-crawler sh -c "gunicorn httpbin:app -b 127.0.0.1:8000 -w 6 --daemon && cd /usr/local/lib/node_modules/crawler && npm install && npm test"

# You can also ssh into the container for easier debugging
$ docker run -i -t node-crawler bash

一些比较困难的待办事项

  • 使用zombie来处理有复杂ajax的页面
  • Refactoring the code to be more maintainable重构代码以方便维护
  • 通过Sizzle测试 (JSDOM bug? https://github.com/tmpvar/jsdom/issues#issue/81)
  • 支持Promise
  • 支持Commander
  • 支持中间件
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,718评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,683评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,207评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,755评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,862评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,050评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,136评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,882评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,330评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,651评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,789评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,477评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,135评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,864评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,099评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,598评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,697评论 2 351

推荐阅读更多精彩内容