【爬蟲】nodejs爬鬥魚直播間數據實戰

前提

本項目github地址:https://github.com/janyin/dou...
若是須要,能夠clone到本地css

$ npm install --save
$ node app

打開http://localhost:3030/index.html 可直接查看爬蟲數據html

目標

爬取鬥魚正在直播的主播數據(房間號,在線人數,房間標題,主播名稱,直播分類等等)前端

依賴構建

安裝npm包express+superagent+cheerionode

$ npm install express superagent cheerio --save
  • express:Node.js的Web應用程序框架
  • superagent:小型漸進式客戶端HTTP請求庫,和Node.js模塊具備相同的API,具備許多高級HTTP客戶端功能
  • cheerio:能夠理解爲一個Node.js版本的jquery,用來從網頁中以 css selector取數據,使用方式和jquery基本相同

實現步驟

一、引入依賴並實例化express

const express = require('express');
const superagent = require('superagent');
const cheerio = require('cheerio');
const app = express();

二、定義目標url

const url = 'https://www.douyu.com/directory/all';
const rooturl = 'https://www.douyu.com';

rooturl是鬥魚首頁,url是鬥魚所有直播間第一頁,rooturl後面直播間地址數據要用到jquery

三、發送請求 獲取數據 分析數據 生成頁面數據到前端

  • 用superagent發送get請求到鬥魚,回調函數接受到的數據給cheerio解析,這樣就能夠用jquery選擇器進行操做
  • 使用cheerio.load()解析
  • 打開鬥魚,發現其直播列表均在id爲live-list-contentbox的ul裏,用jquery選擇器獲取全部li並遍歷
  • 在li裏尋找到咱們須要的數據,最後push到data裏git

    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);//目標數據發送給前端

})github

四、監聽端口

app.listen(3030, function () {
    console.log('server is listening port 3030....');
})

最後node這個項目,打開http://localhost:3000/ 獲得咱們須要的數據ajax

  • 以上所有代碼在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就是相應的頁數(這裏是第二頁)chrome

實現爬蟲

一、和剛纔上面同樣

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';

二、聲明一個函數獲取全部的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就有多少express

三、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主要是方便後面頁面提取


四、分析頁面函數

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解析

五、設置靜態文件目錄

app.use(express.static('public'))

app.listen(3030, function () {
    console.log('server is listening port 3030....');
})

六、編寫前端html,展現數據

  • 前端代碼在index.html裏,主要是獲取數據遍歷輸出到表格,還有一個搜索功能(不建議搜索1W以上的數據,會很卡)

圖片描述以上代碼均在app.js裏

相關文章
相關標籤/搜索