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实现的一个静态服务器实例
Dec 06 NodeJs
轻松创建nodejs服务器(5):事件处理程序
Dec 18 NodeJs
Nodejs进阶:基于express+multer的文件上传实例
Nov 21 NodeJs
nodejs获取微信小程序带参数二维码实现代码
Apr 12 NodeJs
NodeJS自定义模块写法(详解)
Jun 27 NodeJs
对mac下nodejs 更新到最新版本的最新方法(推荐)
May 17 NodeJs
nodejs的路径问题的解决
Jun 30 NodeJs
NodeJs项目中关闭ESLint的方法
Aug 09 NodeJs
深入理解NodeJS 多进程和集群
Oct 17 NodeJs
Nodejs实现用户注册功能
Apr 14 NodeJs
linux 下以二进制的方式安装 nodejs
Feb 12 NodeJs
NodeJS多种创建WebSocket监听的方式(三种)
Jun 04 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
ZF等常用php框架中存在的问题
2008/01/10 PHP
基于magic_quotes_gpc与magic_quotes_runtime的区别与使用介绍
2013/04/22 PHP
浅析PHP安装扩展mcrypt以及相关依赖项(PHP安装PECL扩展的方法)
2013/07/05 PHP
利用curl抓取远程页面内容的示例代码
2013/07/23 PHP
PHP将字符分解为多个字符串的方法
2014/11/22 PHP
PHP jQuery+Ajax结合写批量删除功能
2017/05/19 PHP
PHPExcel中文帮助手册|PHPExcel使用方法(分享)
2017/06/09 PHP
PHP中abstract(抽象)、final(最终)和static(静态)原理与用法详解
2020/06/05 PHP
复制本贴标题和地址的js代码
2008/07/01 Javascript
JS和JQUERY获取页面大小,滚动条位置,元素位置(示例代码)
2013/12/14 Javascript
Jquery 返回json数据在IE浏览器中提示下载的问题
2014/05/18 Javascript
node.js中的fs.fsync方法使用说明
2014/12/15 Javascript
jQuery模拟select实现下拉菜单功能
2016/06/20 Javascript
vue深入解析之render function code详解
2017/07/18 Javascript
将 vue 生成的 js 上传到七牛的实例
2017/07/28 Javascript
React Native验证码倒计时工具类分享
2017/10/24 Javascript
[03:43]TI9战队采访——PSG.LGD
2019/08/22 DOTA
python实现读取excel写入mysql的小工具详解
2017/11/20 Python
解决python ogr shp字段写入中文乱码的问题
2018/12/31 Python
Python时间和字符串转换操作实例分析
2019/03/16 Python
基于Python函数和变量名解析
2019/07/19 Python
Python input函数使用实例解析
2019/11/22 Python
pytorch中的transforms模块实例详解
2019/12/31 Python
基于logstash实现日志文件同步elasticsearch
2020/08/06 Python
Selenium结合BeautifulSoup4编写简单的python爬虫
2020/11/06 Python
Python Selenium异常处理的实例分析
2021/02/28 Python
css3模拟jq点击事件的实例代码
2017/07/06 HTML / CSS
Intersport西班牙:在线体育商店
2019/11/06 全球购物
JSP&Servlet技术面试题
2015/05/21 面试题
舞蹈比赛获奖感言
2014/02/04 职场文书
《临死前的严监生》教学反思
2014/02/13 职场文书
2015暑期爱心支教策划书
2015/07/14 职场文书
三严三实学习心得体会(精选N篇)
2016/01/05 职场文书
2016优秀青年志愿者事迹材料
2016/02/25 职场文书
python基于tkinter制作m3u8视频下载工具
2021/04/24 Python
Python实现简单得递归下降Parser
2022/05/02 Python