前提
本项目github地址:https://github.com/janyin/dou...
如果需要,可以clone到本地
$ npm install --save
$ node app
打开http://localhost:3030/index.html 可直接查看爬虫数据
目标
爬取斗鱼正在直播的主播数据(房间号,在线人数,房间标题,主播名称,直播分类等等)
依赖构建
安装npm包express+superagent+cheerio
$ npm install express superagent cheerio --save
- express:Node.js的Web应用程序框架
- superagent:小型渐进式客户端HTTP请求库,和Node.js模块具有相同的API,具有许多高级HTTP客户端功能
- cheerio:可以理解为一个Node.js版本的jquery,用来从网页中以 css selector取数据,使用方式和jquery基本相同
实现步骤
1、引入依赖并实例化express
const express = require('express');
const superagent = require('superagent');
const cheerio = require('cheerio');
const app = express();
2、定义目标url
const url = 'https://www.douyu.com/directory/all';
const rooturl = 'https://www.douyu.com';
rooturl是斗鱼首页,url是斗鱼全部直播间第一页,rooturl后面直播间地址数据要用到
3、发送请求 获取数据 分析数据 生成页面数据到前端
- 用superagent发送get请求到斗鱼,回调函数接受到的数据给cheerio解析,这样就可以用jquery选择器进行操作
- 使用cheerio.load()解析
- 打开斗鱼,发现其直播列表均在id为live-list-contentbox的ul里,用jquery选择器获取所有li并遍历
-
在li里寻找到我们需要的数据,最后push到data里
app.get('/', function (req, response) { // 声明get请求在指定的路径下调用相应的回调函数 let data = [];//存放获取的数据 superagent.get(url).end(function (err, res) {//发起get请求 if (err) { console.log(err); } else { console.log('状态码:' + res.status); let $ = cheerio.load(res.text);//使用cheerio解析数据 $('#live-list-contentbox li').each(function (i, ele) { //获取目标数据 并遍历存放到data中 let href = rooturl + $(ele).find('a.play-list-link').attr('href');//href是存放的直播间id,加rooturl生成直播间链接 let lives = { name: $(ele).find('span.dy-name').text(), num: $(ele).find('span.dy-num').text(), title: $(ele).find('.mes-tit>h3').text().trim(), links: href,//直播间链接 }; data.push(lives); }) } response.send(data);//目标数据发送给前端
})
4、监听端口
app.listen(3030, function () {
console.log('server is listening port 3030....');
})
最后node这个项目,打开http://localhost:3000/ 得到我们需要的数据
- 以上全部代码在first.js里. 爬虫数据部分结果:
进阶爬虫
-
思考:这只是斗鱼第一页主播的数据,如果是100页的数据,或者全部呢?
这时候就需要async,不可能同步发100个请求,容易被误以为恶意攻击 - Async提供了直接,强大的函数来处理异步JavaScript,虽然最初设计用于Node.js,但它也可以直接在浏览器中使用
$ npm install async --save
分析页面
100个页面可以先获取100个相应的url,但是发现斗鱼切换到第二页的时候其url并没有改变,
通过chrome devtools发现在切换页面时的ajax请求。
发现ajax请求的url是https://www.douyu.com/gapi/rk... ,后面加的/2就是相应的页数(这里是第二页)
实现爬虫
1、和刚才上面一样
const express = require('express');
const superagent = require('superagent');
const async = require('async');
const app = express();
const rooturl = 'https://www.douyu.com/gapi/rkc/directory/0_0';
2、声明一个函数获取所有的url
function geturls(num) {
let href = [];
let urls = [];
for (let i = 1; i <= num; i++) {
href.push('/' + i);
}
href.forEach(function (ele) {
urls.push(rooturl + ele);
})
return urls;
}
传进去的num是多少,返回的url就有多少
3、async异步发送请求
app.get('/data', function (req, res) {
let urls = geturls(100); //获取100个url
let datas = []; //存放目标数据
async.mapLimit(urls,25,function (url, callback) { //异步发送请求
fetchPage(url, callback);//分析数据并提取
}, function (err, result) {
console.log('分析完成!');
res.send(datas);//发送数据给前端
});
})
async.mapLimit(coll, limit, iteratee, callback)
- coll是迭代的集合,就是数组存放需要发送请求的url
- limit一次最大异步操作数
- 一个异步函数,用于应用于每个项目 coll
- callback可选,所有iteratee 函数完成或发生错误时调用的回调。
ps:最后一个函数里result参数的数据和datas数组数据是一样的,发送datas主要是方便后面页面提取
4、分析页面函数
function fetchPage(url, callback) {
superagent.get(url).end(function (err, sres) {
if (err) {
console.log(err);
} else {
let item = JSON.parse(sres.text);//解析json数据
let list = item.data.rl;
list.forEach(function (ele) {//提取需要的数据
let obj = {
name: ele.nn,
id: ele.rid,
online: ele.ol,
title: ele.rn,
class: ele.c2name,
};
datas.push(obj);
});
callback(null, datas);//这个datas会发送给result
}
})
}
})
因为ajax请求直接返回的是json数据就不需要上面的cheerio解析
5、设置静态文件目录
app.use(express.static('public'))
app.listen(3030, function () {
console.log('server is listening port 3030....');
})
6、编写前端html,展示数据
- 前端代码在index.html里,主要是获取数据遍历输出到表格,还有一个搜索功能(不建议搜索1W以上的数据,会很卡)
以上代码均在app.js里
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。