完整代码下载地址:https://github.com/Reda011/Node-CrawlData.git
环境搭建
必须安装Node,我装的是8.11.2版本,Mac开发;
使用到的一些第三方库:
- 后端服务:
express
- 发出http请求:
superagent
- 控制并发请求:
async
+eventproxy
- 分析网页内容:
cheerio
直接配置一下package.json:
{ "name": "spider", "version": "0.0.0", "description": "learn nodejs on github", "scripts": { "start": "node app.js" }, "dependencies": { "async": "^2.0.0-rc.6", "cheerio": "^0.20.0", "eventproxy": "^0.3.4", "express": "^4.9.5", "superagent": "^2.3.0" } }
配置好后 nom install 安装所需依赖;
接下来开始写爬虫。
后台服务部分
实现的功能是接收前端请求启动爬虫,完成信息爬取之后将信息返回给前端。后台服务部分我这里使用了 express
框架,这里比较简单也可以使用原生的 http
模块。简单框架如下:
var express = require('express'); var app = express(); app.get('/', function (req, res, next) { // your code here }); app.listen(3000, function (req, res) { console.log('app is running at port 3000'); });
在 get
处理中插入我们的响应代码,包括启动爬虫,结果信息输出等。
文章链接的爬取
superagent.get(Url).end(function (err, res) { if (err) { return next(err); } // your code here });
Url
为我们请求的地址,使用 get
的方式请求,其实效果跟你用浏览器打开 Url
的效果是一样的,返回来的数据都放在 res
中,对 res
分析就可以得到我们想要的数据了。
数据的处理
这里我们用到的是 cheerio
这个库,他可以让我们以 jQuery
的方式操作返回的数据,实在太贴心了。
注:语法大体跟jquery一致,API可查看:https://cnodejs.org/topic/5203a71844e76d216a727d2e
// 提取作者博客链接,注意去重 var $ = cheerio.load(sres.text); $('.blog_list').each(function (i, e) { var u = $('.nickname', e).attr('href'); if (authorUrls.indexOf(u) === -1) { authorUrls.push(u); } });
文章作者信息的爬取
superagent.get(myurl) .end(function (err, ssres) { if (err) { callback(err, myurl + ' error happened!'); } var $ = cheerio.load(ssres.text); var result = { userId: url.parse(myurl).pathname.substring(1), userName: $(".name #uid").text(), blogTitle: $(".title-blog a").text(), visitCount: $('.grade-box dl').eq(1).children('dd').attr("title"), score: $('.grade-box dl').eq(2).children('dd').attr("title"), /* oriCount: parseInt($('#blog_statistics>li').eq(0).text().split(/[::]/)[1]), copyCount: parseInt($('#blog_statistics>li').eq(1).text().split(/[::]/)[1]), trsCount: parseInt($('#blog_statistics>li').eq(2).text().split(/[::]/)[1]), */ cmtCount: parseInt($('#blog_statistics>li').eq(3).text().split(/[::]/)[1]) }; callback(null, result); });
这里可以根据自己需要,自行筛选数据。
并发的控制
因为我们的请求都是异步的,所以需要执行成功的回调函数中执行下一步操作,在多并发的情况下,就需要一个计数器来判断是否所有并发均已成功执行完。这里用到的是 eventproxy
这个库来替我们管理并发结果。
我们爬取CSDN上web前端前3页,所以我们要执行 3 次爬取文章链接,用 eventproxy
的写法就是:
var baseUrl = 'http://blog.csdn.net/web/index.html'; var pageUrls = []; for (var _i = 1; _i < 4; _i++) { pageUrls.push(baseUrl + '?&page=' + _i); } ep.after('get_topic_html', pageUrls.length, function (eps) { // 文章链接都已经爬取完了 }); pageUrls.forEach(function (page) { superagent.get(page).end(function (err, sres) { // 文章链接的爬取 ep.emit('get_topic_html', 'get authorUrls successful'); }); });
简单来说,就是会检测 'get_topic_html'
的emit事件,发生指定次数之后就调用 ep.after
函数。
并发请求数控制
本来呢,到这里就完了,但是我们爬取作者信息时都是用异步操作的,所以同时可能会有几十甚至几百个请求同时发送给目标网站。出于安全角度考虑,目标网站可能会拒绝我们的请求,所以我们要控制并发数量,这里我们用的是 async
这个库来实现。
这里 authorUrls
是我们前一步爬取好的作者链接数组,async
会根据数组长度依次执行。之前在作者信息爬取部分我们使用了回调函数返回数据,这个也是async
提供的接口。最终数组中所有元素都被执行了一遍之后,就会将 callback
返回的数据放入 result
数组中,将这个数组返回给前端即可。
效果
通过 node app.js
执行后台程序,在 postman 中输入 http://localhost:3000
查看结果:
如上,就算完成了,还可以用它去爬取别的想爬的数据,
完整代码在我的GitHub-->https://github.com/Reda011/Node-CrawlData.git