Node.js Request+Cheerio实现一个小爬虫-基

作者: 吃土的小此方 | 来源:发表于2017-01-15 12:41 被阅读0次

Node.js Request+Cheerio实现一个小爬虫-基础功能实现1:内容抓取
Node.js Request+Cheerio实现一个小爬虫-基础功能实现2:文件写入
Node.js Request+Cheerio实现一个小爬虫-基础功能实现3:流程控制及并发控制
Node.js Request+Cheerio实现一个小爬虫-番外篇:代理设置

上一篇中虽然成功抓下数据了,但是在写入文件中去的时候却发生了问题。我们抓到的数据并没有写到文件里去。其实是因为Node采用了大量的异步操作,对于一些比较花时间的任务并不会按照我们写的顺序执行。对于后续的任务一般都是采用回调函数的方式来执行。这一部分可以参照阮一峰老师的文章JavaScript 标准参考教程(alpha)中Node.js一部分。


那么就来改一下代码,把文件写入的操作塞到request函数里面去。

const request = require('request');
const cheerio = require('cheerio');
const fs = require('fs');

// url 和头部的设定省略

var shopLists = [];

request(option, function(error, response, body) {
    if (!error && response.statusCode == 200) {

        var $ = cheerio.load(body, {
            ignoreWhitespace: true,
            xmlMode: true
        });

        var shopInfo = {
            pageNo: option.url.match(/g\d+p(\d+)/)[1],
            pageURL: option.url,
            info: []
        };

        var shopList = $('div#shop-all-list').find('a[data-hippo-type = "shop"]');

        shopList.each(function(no, shop) {
            let info = {};
            info.no = no + 1;
            info.name = $(shop).attr('title');
            info.url = $(shop).attr('href');
            shopInfo.info.push(info);
        });

        shopLists.push(shopInfo);

        // 在这里加入写进文件的函数
        fs.writeFile(FILE_PATH + FILE_NAME, shopLists 'utf-8', function(err) {
            if (err) {
                console.error("文件生成时发生错误.");
                throw err;
            }
            console.info('文件已经成功生成.');
        });
    }
});

好了,这样一来就能把想要的shopLists的内容写入到文件中去了。但是用writeFile方法的话,在要写入多条数据的情况下,每次写入数据时都是覆盖而不是追加。所以多条数据的情况下,实际上最后只会写入一条数据。这个问题只要稍稍修改一下文件写入的方法就行了。

// 将原来的write方向改为append方法
// 判断一下文件是否已经存在,如果存在那么就追加,否则就先生成一个文件。
fs.exists(FILE_PATH + FILE_NAME, function(exits) {
    if (exits) {
        fs.appendFile(FILE_PATH + FILE_NAME, shopLists 'utf-8', function(err) {
            if (err) {
                console.error("文件生成时发生错误.");
                throw err;
            }
        });
    } else {
        console.info('文件不存在,将生成新文件.');
        // 对于写入的内容shopLists,最好可以用JSON.stringify转化一下。
        //如果把数组直接写入文件的话,很可能会得到 [Object] 这样的形式
        fs.writeFile(FILE_PATH + FILE_NAME, shopLists 'utf-8', function(err) {
            if (err) {
                console.error("文件生成时发生错误.");
                throw err;
            }
            console.info('文件已经成功生成.');
        });
    }
});

那么这样一来我们要的内容就能顺利被写到文件中去了。就像前面说的,问题是解决一个又来一个的。因为Node异步执行的原因,在有多条请求的时候,我们是不知道哪条请求会先执行完。以上面的代码为例,虽然我们可能是按照1,2,3的顺序传入的url来发起请求,但实际上可能得到的是3,2,1这样的结果。那么还是以上面作为例子。我们可以对shopLists的长度进行判断,当shopLists的长度达到了我们的要求,对其排序后写到文件中去。(相当于设置了一个计数器)

// 设定一个目标长度
const DATA_LENGTH = 50;

// 省略的部分与前面相同

request(option, function(error, response, body) {
    // 省略的部分与前面相同

        shopLists.push(shopInfo);

        // 每次push之后对长度进行一次检查
        doWirteFile(shopLists);
    }
});

function doWirteFile(shopLists, DATA_LENGTH){
    if(shopLists.length === DATA_LENGTH){
        // 执行文件写入操作
    }
}

这是一个比较简单的方法。当然也可以使用emit方法对每次push进行监听也能达到同样的效果。但是如果我们不知道需要的数组的长度的话,那么这样的方法就不太适用了。对于这样的情况就留到下次再说吧。

相关文章

网友评论

    本文标题:Node.js Request+Cheerio实现一个小爬虫-基

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