火力全开!Node多进程爬虫示例

in Node.js with 1 comment

前言

最近有看Node的多进程,所以用Nodecluster写了一个抓取豆瓣电影的小玩意(豆瓣表示,为什么你们每次写爬虫都喜欢拿我举例子...)。
Nodecluster模块写的非常细,各种Api也写得非常详细,接下来我会梳理一下我大致的流程。
代码已经上传到GitHub

流程

首先我们先根据官方提供的接口写一个简单的可运行的demo:

let cluster = require('cluster'), cpuNums = require('os').cpus().length;

if (cluster.isMaster) {

    for (let i = 0; i < cpuNums; ++i) {
        let worker = cluster.fork();

        worker.send('hello , this is from master');
    }

} else {

    process.on('message', (msg) => {
        console.log(msg);
        console.log(`i have received your message , my pid is ${process.pid}`);
    })
}

运行结果:

e093f1a3-b69c-4d2f-aa08-c6e48f2b4565.png

正如上图所示,我们会根据我们运行服务器的cpu核数来分配worker,也就是我们所说的多进程,来帮助我们去同步分化实现一个耗时很长的执行流程。
cluster.fork()会帮助我们新建一个新的工作进程,当然,正如worker可以sendprocess可以监听message,我们的cluster其实也可以监听fork,来帮助我们去实现一些初始化的工作。具体的更多的api请参考官方文档。

虽然说我们初步实现了一个简单的多进程,但是有没有发现,其实这里面有一个较大的问题,那就是我们每次fork的时候,整个流程都会重新执行一次,我们可以加一行代码予以验证:

330afc80-ffe3-45b1-9564-1c845d43aeff.png

这很显然不符合我们在工作中的实际流程,因此,我们可以继续阅读官方的文档,一定有提供另外的方法来让我们的masterworker分离。果然,我们很快就找到了我们想要的结果:

用于修改默认'fork' 行为。一旦调用,将会按照cluster.settings进行设置。

通过阅读官方文档,我们发现,其实是有提供一个clusterMaster的方法,来辅助我们构建我们的worker,因此,我们可以通过这个方法来帮助我们达到实现分离的目的。

let cluster = require('cluster'), cpuNums = require('os').cpus().length;

//生成新进程时的配置
// demo_2_mastet.js
cluster.setupMaster({
    exec: 'demo_2_worker.js',
    args: ['--use', 'http']
});

for (let i = 0; i < cpuNums; ++i) {
    let worker = cluster.fork();

    worker.send('hello , this is from master');
}
// demo_2_worker.js
process.on('message', (msg) => {
    console.log(msg);
    console.log(`i have received your message , my pid is ${process.pid}`);
});

59425e11-9154-44d6-a5b9-591f4e76f292.png

很显然,我们的分离是有作用的,这样,我们离我们的多进程爬虫就又进了一步。

接下来就是我们要抓取的过程了,抓取主要是采用了superagent这个模块来帮助我们实现,API非常的简单,而豆瓣的接口也非常方便分析,这里就不多赘述了,这里特别感谢豆瓣

// spider.js
let superagent = require('superagent'), fs = require('fs');
let url = 'https://movie.douban.com/j/search_subjects', filePath = './data/movie.txt';

module.exports = (page) => {
    return new Promise((resolve, reject) => {
        superagent
            .get(url)
            .query({
                'type': 'movie',
                'tag': '热门',
                'sort': 'recommend',
                'page_limit': 20,
                'page_start': page
            })
            .set('Accept', 'application/json, text/javascript, */*; q=0.01')
            .set('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')
            .end(function (err, res) {
                fs.appendFile(filePath, res.text, (err) => {
                    if (err) return reject(err);
                    console.log('ok');
                    return resolve('write success');
                })
            })
    });
};

这样,我们就能把最近热门的电影放到我们的movie.txt文件中了。

Responses
  1. 苍老师

    苍老师觉得很ol

    Reply