zoukankan      html  css  js  c++  java
  • 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下载源代码

    欢迎拍砖 :)

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

  • 相关阅读:
    设计模式复习【1】- 设计原则
    Java8的学习笔记
    Gson关于抽象类的序列化与反序列化
    关于一个Java web与JFrame的深度结合
    《重构》笔记
    JAVA8 Stream API总结的好的文章 —— 持续更
    Spring Boot引入Thymeleaf前端框架的诸多问题
    敏捷开发:原则,模式与实践——第8章 单一职责原则SRP
    maven 你应该懂得那些事
    redis之单机和主从环境搭建
  • 原文地址:https://www.cnblogs.com/xbblogs/p/8029891.html
Copyright © 2011-2022 走看看