【爬虫】nodejs爬斗鱼直播间数据实战

1

前提

本项目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里

你可能感兴趣的

载入中...