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

news/2024/7/18 20:00:48 标签: 爬虫, 前端, json

前提

本项目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://www.niftyadmin.cn/n/1774789.html

相关文章

推荐系统之 BPR 算法及 Librec的BPR算法实现【2】

先前的是&#xff1a;推荐系统之 BPR 算法及 Librec的BPR算法实现【1】 LibREC源码里的BPR算法的输入比较是&#xff1a;“&#xff08;购买点击&#xff09;v.s.没出现的”&#xff0c;先前有修改过一次是让输入比较对为&#xff1a;“购买v.s. 点击”。现在的情况是&#xff…

win10系统出现“服务主机:本地服务(无网络)(6)”占用大量内存和CPU情况的解决方案

本人的电脑是联想G480&#xff0c;四年前的老电脑&#xff0c;现在跑的是win10系统&#xff0c;但是老是出现电脑卡死不动的情况。后来一看是<服务主机&#xff1a;本地服务&#xff08;无网络)&#xff08;6&#xff09;>占用大量内存和CPU&#xff0c;通过测试&#xf…

Canonical发布Ubuntu 14.04 LTS 内核回归新补丁

2019独角兽企业重金招聘Python工程师标准>>> 导读上周&#xff0c;Canonical发布了针对所有受支持的Ubuntu Linux版本的新内核安全更新&#xff0c;以解决最近披露的L1 Terminal Fault&#xff08;L1TF&#xff09;漏洞CVE-2018-3620和CVE-2018-3646。内核安全更新解…

PostgreSQL入门指南

默认端口&#xff1a;5432创建用户与数据库PostgreSQL初次安装后&#xff0c;默认会生成一个名为postgres的数据库和一个名为postgres的数据库用户。这里需要注意的是&#xff0c;同时还生成了一个名为postgres的Linux系统用户。下面&#xff0c;我们使用postgres用户&#xff…

while与break、continue、return以及goto的使用

目前在我们项目中用到的while语句还比较多&#xff0c;现在就来总结下while与break、continue、return以及goto一起使用的案例。 &#xff08;1&#xff09;while与break&#xff1a;直接跳出整个循环体 while(flag<5){if(flag 4){break;}printf("flag %d.\n"…

【cookie】cookie和session的终极区别

如果浏览器使用的是 cookie&#xff0c;那么所有的数据都保存在浏览器端&#xff0c;比如你登录以后&#xff0c;服务器设置了 cookie用户名(username),那么&#xff0c;当你再次请求服务器的时候&#xff0c;浏览器会将username一块发送给服务器&#xff0c;这些变量有一定的特…

两个.c文件访问同一个全局变量的用法

上周编程的时候犯了一个错误&#xff0c;以为在一个头文件里面定义一个全局变量&#xff0c;然后两个.c文件包含这个头文件&#xff0c;这两个.c文件就可以同时访问。结果编译报错&#xff0c;理由是重复定义。下面就介绍两种方法&#xff0c;同一个全局变量被两个.c文件访问。…

配置browser-sync 浏览器同步测试工具

配置browser-sync 浏览器同步测试工具 安装依赖 npm i -g browser--sync // 全局安装 ​ npm install --save-dev browser-sync 卸载 npm uninstall --globall browser--sync 注意&#xff1a; 我们在实际开发中通常是将browser-sync配置在项目中&#xff0c;因为clone到本地后…