美文网首页技术栈
[译]Node Crawler:强大的Node开源爬虫

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

作者: pockry | 来源:发表于2017-05-22 16:34 被阅读901次

    自从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
    • 支持中间件

    相关文章

      网友评论

      本文标题:[译]Node Crawler:强大的Node开源爬虫

      本文链接:https://www.haomeiwen.com/subject/vtqixxtx.html