擼個有成就感的爬蟲看電影

春去春又來發表於2018-07-26

背景

  1. 想看電影。
  2. 需要有免費的電影資源。

只要我們有了免費的電影資源後,就可以愉快的看電影了,或者把免費電影連結發給某個姑娘,嘿嘿嘿!

如何獲取電影資源

國內的視訊網站有:騰訊視訊、愛奇藝、優酷等等,今天就看愛奇藝上的電影好了。

  • 電影資源這些資料都在 html 頁面上,所以先擼一個通過請求 url 獲取 html 頁面的方法。

    ps:也可以使用現成的庫 比如 Axios。

    fetch.js

        const http = require('http');
        const https = require('https');
        const urlMd = require('url');
        module.exports = function (url, callback){
            let urlInfo = urlMd.parse(url);
            let fetcher = urlInfo.protocol === 'http:' ? http : https;
            let req = fetcher.request({
                hostname: urlInfo.hostname,
                path: urlInfo.path,
            }, (res) => {
                console.log(`狀態碼: ${res.statusCode}`);
                if (res.statusCode === 200) {
                    let content = [];
                    res.on('data', (chunk) => {
                        content.push(chunk);
                    })
        
                    res.on('end', () => {
                        let b = Buffer.concat(content);
                        callback && callback(null,b.toString());
                    })
                } else {
                    callback(new Error(`狀態碼:${res.statusCode}`));
                }
            })
        
            req.end();
            req.on('error', (err) => {
                callback(err);
            })
        }
    複製程式碼
    1. 通過 util.parse 解析出使用 http 還是 https
    2. 通過 request 設定請求資訊
    3. 通過 req.end 傳送
    4. 請求成功後,判斷狀態碼 200 為成功,否則為失敗( 304 也可能是成功,這裡沒有擴充套件)

    注意:因為後面要用 util.promisify 來包裹此函式,所以 callback 需要符合 nodejs 規定,第一個引數必須為 err。

  • 尋找電影所在的地址

    1. 開啟愛奇藝
    2. 點選電影頻道
    3. 點選全部

    發現這個頁面滿足了我們的需要,接下來獲取到電影所在的 html 即可。

    擼個有成就感的爬蟲看電影

    擼個有成就感的爬蟲看電影
    當前的url: http://list.iqiyi.com/www/1/-------------11-1-1-iqiyi--.html

    當點選下一頁的時候發現 url 變成了:http://list.iqiyi.com/www/1/-------------11-2-1-iqiyi--.html

    對比發現 url 只改變了一個數字,那麼是不是它可以控制頁碼呢?,驗證後果然如此。

    index.js

        function getSourceURL(index) {
            return `http://list.iqiyi.com/www/1/-------------11-${index}-1-iqiyi--.html`
        }
    複製程式碼
    1. 通過 index 控制頁碼
    2. 返回url
  • 解析 html 獲取電影資料

    知道了電影所在的 url,也有了通過 url 獲取 html 頁面資料的方法,那麼接下來就是要解析出 html 內的電影資料咯。(fetch 拉取到的 html 頁面資料都是字串形式)

    index.js

        const jsdom = require('jsdom');
        const { JSDOM } = jsdom;
        
        function parseHTML(html) {
            const dom = new JSDOM(html);
            let aList = dom.window.document.querySelectorAll('div.site-piclist_pic > a');
            aList = Array.from(aList);
            return aList.map((a) => {
                return {
                    source: a.href,
                    title: a.title,
                    url: `${config.parseURL}${a.href}`
                }
            });
        }
    複製程式碼

    config.json

         "parseURL":"http://vip.jlsprh.com/index.php?url="
    複製程式碼
    1. 使用 jsdom 庫解析 html
    2. 獲取所有的電影標籤
    3. 返回需要的資料

config.parseURL 為解析視訊的介面地址(通過電影url 可以免費播放,無需會員)

萬里長征 還差一點

接下來通過併發(加快請求速度)來請求電影頁面,解析並儲存到本地。

config.json

     {
        "pageMaxNum":"20",
        "parseURL":"http://vip.jlsprh.com/index.php?url="
    }
複製程式碼

index.js

    const util = require('util');
    const fetch = util.promisify(require('./fetch.js'));
    const jsdom = require('jsdom');
    const { JSDOM } = jsdom;
    const fs = require('fs');
    const config = require('./config.json');
    
    (function () {
        Promise.all(fetchHandler())
            .then(d => parseHTML(d))
            .then(d => saveToFile(d));
    })()
    
    function fetchHandler(){
        let promiseList = [];
        for (let i = 1; i <= config.pageMaxNum; i++) {
            promiseList.push(fetch(getSourceURL(i)));
        }
        return promiseList;
    }
    
    function getSourceURL(index) {
        return `http://list.iqiyi.com/www/1/-------------11-${index}-1-iqiyi--.html`
    }
    
    function parseHTML(html) {
        const dom = new JSDOM(html);
        let aList = dom.window.document.querySelectorAll('div.site-piclist_pic > a');
        aList = Array.from(aList);
        return aList.map((a) => {
            return {
                source: a.href,
                title: a.title,
                url: `${config.parseURL}${a.href}`
            }
        });
    }
    
    function saveToFile(data) {
        let str = JSON.stringify(data);
        fs.writeFile('./data.json', str, { flag: 'w+' }, (err) => {
            if (err) console.log(err);
        })
    }
複製程式碼
  1. 通過 pageMaxNum 欄位來控制拉取的頁碼數和併發的數量。
  2. 利用 util.promisify 使 fetch 返回 promise
  3. 利用 Promise.all 全部請求完成後在處理
  4. 解析 html 取出所需資料
  5. 儲存到本地

結束語

全部擼完後,你會得到一個 data.json 檔案(別忘記執行 node index),裡面包含免費播放的連結地址。後續的話可以在擼一個前臺頁面,基於這些資料可以製作一個小電影網站了~

至此,一個小小的爬蟲就學會了。是不是感覺很有成就感呢,只學習乾巴巴的 API 的話可是相當枯燥,把這些知識轉化為一個小專案,可以提高自己的動力和興趣,把結果分享給朋友的話還能提高自己的成就感,何樂而不為呢。

程式碼連結

點我點我點我

參考

  1. http://es6.ruanyifeng.com/?search=Symbol&x=17&y=10#docs/reflect
  2. http://www.iqiyi.com/
  3. http://nodejs.cn/api/

本專案僅作為個人學習用途,如有侵權請聯絡我刪除該文章

相關文章