首先我們看下數據來源:
來源於這個網站:https://z1.m1907.cn/
可以說這個網站上能找到很多你想看的很多電影或電視劇,最重要的是很多電影電視劇在別的網站是收費的,但是在這里看是免費的,之前也經常在這個網站中看。
不過這個網站有些缺點:在微信中被屏蔽了網址。在誇克瀏覽器上如果播放到某集,誇克播放器就會覆蓋掉原生播放器,導致切換下一集時不好切換過去,因此,希望能開發一個自己的網站,獲取該網站的數據來呈現。
一般來說,我們只需要拿到這些數據的url接口就行了。但是看了這個網站的network請求,發現這個接口的某個參數是可變的,而且還是必須要的。
這個url就算獲取視頻列表的接口,但是中間的z參數是必填的,而且每過一段時間就需要更換參數。
這個參數它不來源於上一個接口的某個結果,它是通過js進行了md5之后生成的。這就難辦了。怎么去獲取這個值呢?
我們點擊這里,然后點擊這個小圖標
斷點發現,生成z參數的就是這個p變量。
然后,因為內部代碼已被壓縮,所以不好理清楚里面的邏輯了,所以就采用了fiddler抓包工具,將這個js文件進行代理到本地js中。篡改js文件做一些外加功能。
我使用fiddler代理篡改了這段代碼,就是將這個z參數顯示在dom中。
因此,dom中就有了這么一個dom元素,那么這有什么用呢?這樣我就能在自己的服務器中拿到這個值?
是的,我使用的是nodejs。前段時間在網上找到了一個有意思npm包,用來在服務器中模擬瀏覽器操作,自然在服務器中就能獲取到瀏覽器中渲染的dom了。那就是標題里說的puppeteer。
因為之前用fiddler代理將這個只放在了dom中,因此我們也就可以使用puppeteer模塊從dom中拿到這個值,曲線救國。
請看實現(使用koajs服務端,ctx.response.body
即可輸出這個z參數)
const puppeteer = require('puppeteer'); /** * 獲取https://z1.m1907.cn/的動態z 需求開fiddler */ module.exports = async(ctx) => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://z1.m1907.cn/?jx=bilibili'); //注入腳本 const dimensions = await page.evaluate(async() => { let z = '' if (document.querySelector('#z')) { z = document.querySelector('#z').innerText; } return { z, } }); await browser.close(); ctx.response.body = dimensions; return dimensions;//這個return是給下一個接口調用的 }
page.evaluate
可以將瀏覽器的js代碼注入到dimensions的隱藏瀏覽器中。就能通過document.querySelector('#z').innerText
拿到那個z參數,然后通過node返回了。
拿到了。這個數據一般能使用幾個小時,幾個小時后又需要重新獲取新的值了,重新執行接口即可。
拿到這樣要獲取數據就容易多了。
看后續寫法:
const { loadPage } = require('../../utils/utils'); const getId = require('./getId'); const setting = require('./setting'); /** * 主程序 */ const videos = async(ctx) => { const { title = 'bilibili', z = null } = ctx.query // console.log(setting.z) z && (setting.z = z); //手動輸入z參數 const content = await loadPage(`https://a1.m1907.cn/api/v/?z=${setting.z}&jx=${title}&s1ig=11402&g=`); if (content.includes('獲取json版api地址')) {//獲取數據錯誤 重新獲取z參數 const obj = await getId(ctx); console.log(obj) setting.z = obj.z await videos(ctx) return; } ctx.response.body = content; } module.exports = videos;
loadPage
是封裝的請求頁面的方法,getId
是之前用於返回z參數的方法,setting
是用於儲存獲取到的z參數,失效了才重新獲取。
這樣就能返回數據了。
訪問接口,拿到當前電視劇/電影的所有劇集的m3u8播放地址,這樣在支持m3u8的播放器中就可以直接播放了。
(完)