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+express+html5 实现拖拽上传
Aug 08 NodeJs
轻松创建nodejs服务器(8):非阻塞是如何实现的
Dec 18 NodeJs
nodejs事件的监听与触发的理解分析
Feb 12 NodeJs
NodeJS Web应用监听sock文件实例
Feb 18 NodeJs
nodejs导出excel的方法
Jun 30 NodeJs
nodejs简单实现操作arduino
Sep 25 NodeJs
深入学习nodejs中的async模块的使用方法
Jul 12 NodeJs
详解Nodejs mongoose
Jun 10 NodeJs
nodejs微信开发之自动回复的实现
Mar 17 NodeJs
Nodejs 识别图片类型的方法
Aug 15 NodeJs
nodejs环境使用Typeorm连接查询Oracle数据
Dec 05 NodeJs
如何利用nodejs实现命令行游戏
Nov 24 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
php IP及IP段进行访问限制的代码
2008/12/17 PHP
PHP实现在数据库百万条数据中随机获取20条记录的方法
2017/04/19 PHP
PHP实现验证码校验功能
2017/11/16 PHP
php用户名的密码加密更安全的方法
2019/06/21 PHP
JavaScript 联动的无限级封装类,数据采用非Ajax方式,随意添加联动
2010/06/29 Javascript
$("").click与onclick的区别示例介绍
2014/09/25 Javascript
jquery实现鼠标滑过显示二级下拉菜单效果
2015/08/24 Javascript
分享jQuery封装好的一些常用操作
2016/07/28 Javascript
JS数组去掉重复数据只保留一条的实现代码
2016/08/11 Javascript
基于JS+Canves实现点击按钮水波纹效果
2016/09/15 Javascript
bootstrap监听滚动实现头部跟随滚动
2016/11/08 Javascript
Asp.Net之JS生成分页条的方法
2016/11/23 Javascript
Angular 4.x+Ionic3踩坑之Ionic3.x pop反向传值详解
2018/03/13 Javascript
vue中的v-model原理,与组件自定义v-model详解
2020/08/04 Javascript
vue-cli —— 如何局部修改Element样式
2020/10/22 Javascript
vue+iview分页组件的封装
2020/11/17 Vue.js
[02:19]DOTA2女子战队FOX视频专访:希望更多美眉一起加入
2013/10/15 DOTA
一个基于flask的web应用诞生 记录用户账户登录状态(6)
2017/04/11 Python
基于并发服务器几种实现方法(总结)
2017/12/29 Python
Python实现找出数组中第2大数字的方法示例
2018/03/26 Python
python实现对求解最长回文子串的动态规划算法
2018/06/02 Python
解决Tensorflow 使用时cpu编译不支持警告的问题
2020/02/03 Python
Python3批量创建Crowd用户并分配组
2020/05/20 Python
如何解决flask修改静态资源后缓存文件不能及时更改问题
2020/08/02 Python
通过实例简单了解python yield使用方法
2020/08/06 Python
Python pickle模块常用方法代码实例
2020/10/10 Python
BeautifulSoup获取指定class样式的div的实现
2020/12/07 Python
中兴通讯全球官方网站:ZTE
2020/12/26 全球购物
盛大二次面试题
2016/11/18 面试题
优秀员工表扬信
2014/01/17 职场文书
绿色环保演讲稿
2014/05/10 职场文书
生物科学专业毕业生求职信
2014/06/02 职场文书
2014四风问题对照检查材料范文
2014/09/15 职场文书
学习计划书怎么写
2014/09/15 职场文书
道歉信怎么写
2015/05/12 职场文书
学历证明范文
2015/06/16 职场文书