背景
- 想看電影。
- 需要有免費的電影資源。
只要我們有了免費的電影資源後,就可以愉快的看電影了,或者把免費電影連結發給某個姑娘,嘿嘿嘿!
如何獲取電影資源
國內的視訊網站有:騰訊視訊、愛奇藝、優酷等等,今天就看愛奇藝上的電影好了。
-
電影資源這些資料都在 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); }) } 複製程式碼
- 通過 util.parse 解析出使用 http 還是 https
- 通過 request 設定請求資訊
- 通過 req.end 傳送
- 請求成功後,判斷狀態碼 200 為成功,否則為失敗( 304 也可能是成功,這裡沒有擴充套件)
注意:因為後面要用 util.promisify 來包裹此函式,所以 callback 需要符合 nodejs 規定,第一個引數必須為 err。
-
尋找電影所在的地址
- 開啟愛奇藝
- 點選電影頻道
- 點選全部
發現這個頁面滿足了我們的需要,接下來獲取到電影所在的 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` } 複製程式碼
- 通過 index 控制頁碼
- 返回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=" 複製程式碼
- 使用 jsdom 庫解析 html
- 獲取所有的電影標籤
- 返回需要的資料
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);
})
}
複製程式碼
- 通過 pageMaxNum 欄位來控制拉取的頁碼數和併發的數量。
- 利用 util.promisify 使 fetch 返回 promise
- 利用 Promise.all 全部請求完成後在處理
- 解析 html 取出所需資料
- 儲存到本地
結束語
全部擼完後,你會得到一個 data.json 檔案(別忘記執行 node index),裡面包含免費播放的連結地址。後續的話可以在擼一個前臺頁面,基於這些資料可以製作一個小電影網站了~
至此,一個小小的爬蟲就學會了。是不是感覺很有成就感呢,只學習乾巴巴的 API 的話可是相當枯燥,把這些知識轉化為一個小專案,可以提高自己的動力和興趣,把結果分享給朋友的話還能提高自己的成就感,何樂而不為呢。
程式碼連結
參考
- http://es6.ruanyifeng.com/?search=Symbol&x=17&y=10#docs/reflect
- http://www.iqiyi.com/
- http://nodejs.cn/api/