NodeJS制作爬虫全过程


Posted in NodeJs onDecember 22, 2014

今天来学习alsotang的爬虫教程,跟着把CNode简单地爬一遍。

建立项目craelr-demo
我们首先建立一个Express项目,然后将app.js的文件内容全部删除,因为我们暂时不需要在Web端展示内容。当然我们也可以在空文件夹下直接 npm install express来使用我们需要的Express功能。

目标网站分析
如图,这是CNode首页一部分div标签,我们就是通过这一系列的id、class来定位我们需要的信息。
NodeJS制作爬虫全过程

使用superagent获取源数据

superagent就是ajax API来使用的Http库,它的使用方法与jQuery差不多,我们通过它发起get请求,在回调函数中输出结果。

var express = require('express');

var url = require('url'); //解析操作url

var superagent = require('superagent'); //这三个外部依赖不要忘记npm install

var cheerio = require('cheerio');

var eventproxy = require('eventproxy');

var targetUrl = 'https://cnodejs.org/';

superagent.get(targetUrl)

    .end(function (err, res) {

        console.log(res);

    });

它的res结果为一个包含目标url信息的对象,网站内容主要在其text(string)里。
NodeJS制作爬虫全过程

使用cheerio解析

cheerio充当服务器端的jQuery功能,我们先使用它的.load()来载入HTML,再通过CSS selector来筛选元素。

var $ = cheerio.load(res.text);

//通过CSS selector来筛选数据

$('#topic_list .topic_title').each(function (idx, element) {

    console.log(element);

});

其结果为一个个对象,调用 .each(function(index, element))函数来遍历每一个对象,返回的是HTML DOM Elements。
NodeJS制作爬虫全过程

输出 console.log($element.attr('title'));的结果为 广州 2014年12月06日 NodeParty 之 UC 场
之类的标题,输出 console.log($element.attr('href'));的结果为 /topic/545c395becbcb78265856eb2之类的url。再用NodeJS1的url.resolve()函数来补全完整的url。

superagent.get(tUrl)

    .end(function (err, res) {

        if (err) {

            return console.error(err);

        }

        var topicUrls = [];

        var $ = cheerio.load(res.text);

        // 获取首页所有的链接

        $('#topic_list .topic_title').each(function (idx, element) {

            var $element = $(element);

            var href = url.resolve(tUrl, $element.attr('href'));

            console.log(href);

            //topicUrls.push(href);

        });

    });

使用eventproxy来并发抓取每个主题的内容
教程上展示了深度嵌套(串行)方法和计数器方法的例子,eventproxy就是使用事件(并行)方法来解决这个问题。当所有的抓取完成后,eventproxy接收到事件消息自动帮你调用处理函数。

//第一步:得到一个 eventproxy 的实例

var ep = new eventproxy();

//第二步:定义监听事件的回调函数。

//after方法为重复监听

//params: eventname(String) 事件名,times(Number) 监听次数, callback 回调函数

ep.after('topic_html', topicUrls.length, function(topics){

    // topics 是个数组,包含了 40 次 ep.emit('topic_html', pair) 中的那 40 个 pair

    //.map

    topics = topics.map(function(topicPair){

        //use cheerio

        var topicUrl = topicPair[0];

        var topicHtml = topicPair[1];

        var $ = cheerio.load(topicHtml);

        return ({

            title: $('.topic_full_title').text().trim(),

            href: topicUrl,

            comment1: $('.reply_content').eq(0).text().trim()

        });

    });

    //outcome

    console.log('outcome:');

    console.log(topics);

});

//第三步:确定放出事件消息的

topicUrls.forEach(function (topicUrl) {

    superagent.get(topicUrl)

        .end(function (err, res) {

            console.log('fetch ' + topicUrl + ' successful');

            ep.emit('topic_html', [topicUrl, res.text]);

        });

});

结果如下

NodeJS制作爬虫全过程

扩展练习(挑战)

获取留言用户名和积分

NodeJS制作爬虫全过程

在文章页面的源码找到评论的用户class名,classname为reply_author。console.log第一个元素 $('.reply_author').get(0)可以看到,我们需要获取东西都在这里头。
NodeJS制作爬虫全过程

首先,我们先对一篇文章进行抓取,一次性把需要的都得到即可。

var userHref = url.resolve(tUrl, $('.reply_author').get(0).attribs.href);

console.log(userHref);

console.log($('.reply_author').get(0).children[0].data);

我们可以通过https://cnodejs.org/user/username抓取积分信息

$('.reply_author').each(function (idx, element) {

var $element = $(element);

console.log($element.attr('href'));

});

在用户信息页面 $('.big').text().trim()即为积分信息。

使用cheerio的函数.get(0)为获取第一个元素。

var userHref = url.resolve(tUrl, $('.reply_author').get(0).attribs.href);

console.log(userHref);

这只是对于单个文章的抓取,对于40个还有需要修改的地方。

NodeJs 相关文章推荐
nodejs读取memcache示例分享
Jan 02 NodeJs
轻松创建nodejs服务器(9):实现非阻塞操作
Dec 18 NodeJs
nodejs 整合kindEditor实现图片上传
Feb 03 NodeJs
NodeJS整合银联网关支付(DEMO)
Nov 09 NodeJs
基于Nodejs利用socket.io实现多人聊天室
Feb 22 NodeJs
详解nodejs微信公众号开发——6.自定义菜单
Apr 13 NodeJs
Nodejs搭建wss服务器教程
May 24 NodeJs
nodejs结合Socket.IO实现的即时通讯功能详解
Jan 12 NodeJs
nodejs前端模板引擎swig入门详解
May 15 NodeJs
NodeJS实现同步的方法
Mar 02 NodeJs
Nodejs文件上传、监听上传进度的代码
Mar 27 NodeJs
基于NodeJS开发钉钉回调接口实现AES-CBC加解密
Aug 20 NodeJs
nodejs中操作mysql数据库示例
Dec 20 #NodeJs
轻松创建nodejs服务器(10):处理上传图片
Dec 18 #NodeJs
轻松创建nodejs服务器(10):处理POST请求
Dec 18 #NodeJs
轻松创建nodejs服务器(7):阻塞操作的实现
Dec 18 #NodeJs
轻松创建nodejs服务器(8):非阻塞是如何实现的
Dec 18 #NodeJs
轻松创建nodejs服务器(9):实现非阻塞操作
Dec 18 #NodeJs
轻松创建nodejs服务器(6):作出响应
Dec 18 #NodeJs
You might like
模拟flock实现文件锁定
2007/02/14 PHP
php中将网址转换为超链接的函数
2011/09/02 PHP
thinkphp文件引用与分支结构用法实例
2014/11/26 PHP
php实现搜索一维数组元素并删除二维数组对应元素的方法
2015/07/06 PHP
Yii1.1中通过Sql查询进行的分页操作方法
2017/03/16 PHP
php + WebUploader实现图片批量上传功能
2019/05/06 PHP
google地图的路线实现代码
2009/08/20 Javascript
一些实用的jQuery代码片段收集
2011/07/12 Javascript
jquery 操作日期、星期、元素的追加的实现代码
2012/02/07 Javascript
js实现屏蔽默认快捷键调用自定义事件示例
2013/06/18 Javascript
让IE8浏览器支持function.bind()方法
2014/10/16 Javascript
javascript 中__proto__和prototype详解
2014/11/25 Javascript
javascript实现一个数值加法函数
2015/06/26 Javascript
js图片轮播手动切换效果
2015/11/10 Javascript
基于Jquery和CSS3制作数字时钟附源码下载(CSS3篇)
2015/11/24 Javascript
input 禁止输入特殊字符的四种实现方式
2016/08/24 Javascript
Bootstrap4如何定制自己的颜色和风格
2018/02/26 Javascript
解决vue单页使用keep-alive页面返回不刷新的问题
2018/03/13 Javascript
JS实现求字符串中出现最多次数的字符和次数示例
2019/07/05 Javascript
使用VScode 插件debugger for chrome 调试react源码的方法
2019/09/13 Javascript
[01:01:24]DOTA2上海特级锦标赛A组败者赛 EHOME VS CDEC第三局
2016/02/25 DOTA
[01:12]快闪回顾DOTA2亚洲邀请赛(DAC) 静候2018新征程开启
2018/03/11 DOTA
详细解析Python中__init__()方法的高级应用
2015/05/11 Python
用Python计算三角函数之atan()方法的使用
2015/05/15 Python
Python编程之变量赋值操作实例分析
2017/07/24 Python
Python基于Flask框架配置依赖包信息的项目迁移部署
2018/03/02 Python
python 读取txt,json和hdf5文件的实例
2018/06/05 Python
在Mac上删除自己安装的Python方法
2018/10/29 Python
CSS3 rgb and rgba(透明色)的使用详解
2020/09/25 HTML / CSS
大学生预备党员自我评价分享
2013/11/16 职场文书
人力资源管理系自荐信
2014/05/31 职场文书
初婚初育证明范本
2014/11/24 职场文书
六年级作文之家庭作文
2019/12/12 职场文书
MySQL 慢查询日志深入理解
2021/04/22 MySQL
解决goland 导入项目后import里的包报红问题
2021/05/06 Golang
python 实现图与图之间的间距调整subplots_adjust
2021/05/21 Python