node.js爬虫

这是一个简单的node.js爬虫项目,麻雀虽小五脏俱全。

本项目主要包含一下技术:

  发送http抓取页面(http)、分析页面(cheerio)、中文乱码处理(bufferhelper)、异步并发流程控制(thenjs)

1、为什么选择http模块来发送Http请求下载页面

  社区有很多封装好的Http请求模块,例如:request、needle、node-rest-client等,http有这些模块比拟不了的优势,可以监听抓取的字节流,我们知道要抓取的页面一般会含有汉字,一个汉字是3个字节(也有说4个字节),笔者在node中测试的是3个字节,一个英文字母是1个字节(见下图),node对中文的支持是不友好的,所以就需要借助bufferhelper来解决字节流问题,再使用 iconv-lite模块把buffer转化成utf8格式。

2、使用cheerio分析Html,让你感觉就像是在使用JQuery

3、虽说如今node上已经有异步控制的标准 async/await,但是thenjs,真的很好用,并且效率也不错,本项目主要用了它的异步并行控制 Then.each,了解更多thenjs介绍

4、本项目主要是抓取菜鸟教程的 HTML/CSS 下的8个页面,本项目先抓取 http://www.runoob.com 分析其Html,找到这8个页面的Url,再分别抓取这些页面的Html,写入到本地文件

代码 chong.js :

var http = require('http');
var Then = require('thenjs');
var BufferHelper = require('bufferhelper');
var fs = require('fs');
var cheerio = require('cheerio'); // Html分析模块
var iconv = require('iconv-lite'); // 字符转码模块
var pageUrl = []; //Url集合
var pagesHtml = []; //所有Url获取的Html的集合
var baseUrl = 'http://www.runoob.com';

main();

function main() {
    console.log('Start');
    Then(cont => {
        grabPageAsync(baseUrl, cont)
    }).then((cont, html) => {
        var $ = cheerio.load(html);
        var $html = $('.codelist.codelist-desktop.cate1');
        var $aArr = $html.find('a');
        $aArr.each((i, u) => {
            pageUrl.push('http:' + $(u).attr('href'));
        })
        everyPage(cont);
    }).fin((cont, error, result) => {
        console.log(error ? error : JSON.stringify(result));
        console.log('End');
    })
}

//爬去每个Url
function everyPage(callback) {
    Then.each(pageUrl, (cont, item) => {
        grabPageAsync(item, cont);
    }).then((cont, args) => {
        pagesHtml = args;
        createHtml(cont);
    }).fin((cont, error, result) => {
        callback(error, result);
    })
}

//创建Html文件
function createHtml(callback) {
    Then.each(pagesHtml, (cont, item, index) => {
        var name = pageUrl[index].substr(pageUrl[index].lastIndexOf('/') + 1);
        fs.writeFile(__dirname + '/grapHtml/' + name, item, function(err) {
            err ? console.error(err) : console.log('写入成功:' + name);
            cont(err, index);
        });
    }).fin((cont, error, result) => {
        callback(error, result);
    })
}

// 异步爬取页面HTML 
function grabPageAsync(url, callback) {
    http.get(url, function(res) {
        var bufferHelper = new BufferHelper();
        res.on('data', function(chunk) {
            bufferHelper.concat(chunk);
        });
        res.on('end', function() {
            console.log('爬取 ' + url + ' 成功');
            var fullBuffer = bufferHelper.toBuffer();
            var utf8Buffer = iconv.decode(fullBuffer, 'UTF-8');
            var html = utf8Buffer.toString()
            callback(null, html);
        });
    }).on('error', function(e) {
        // 爬取成功
        callback(e, null);
        console.log('爬取 ' + url + ' 失败');
    });
}

运行: 

抓取的页面结果:

Github下载源代码

欢迎拍砖 :)

本文原创转载请注明出处!

原文地址:https://www.cnblogs.com/xbblogs/p/8029891.html