獲取網頁中的視訊下載地址(用headless browser)
介紹
前面通過兩篇文章講了怎麼去抓取HTTP的請求包,包括用代理伺服器和抓包的方法。正因為現在的視訊網站的視訊地址都不是直接在html頁面上獲取的,視訊的獲取是通過瀏覽器動態解釋js指令碼,再向視訊伺服器發去視訊請求。所以我們通過獲取瀏覽器產生的HTTP請求來獲得視訊的下載地址。
思路
直接用firefox
我們想到了可以用動態渲染js指令碼的程式,最常見的是瀏覽器。我們通過命令執行
firefox http://the.video.url
就可以用firefox開啟網址了。可是我們沒辦法在沒有顯示的情況下這樣使用,但是我們後面有方法解決這個問題。
python+selenium+Phantomjs
因為我們需要在沒有介面顯示的情況下渲染JS指令碼,我們還想到了python+selenium+Phantomjs來動態渲染頁面。Phantomjs是一個headless browser(Headless Browser就是沒有介面的瀏覽器)。
可是Phantomjs 1.5版本以後,就不再支援flash外掛了。換句話說,雖然Phantomjs能動態載入JS指令碼,但是沒辦法渲染視訊。所以不會發出獲取視訊的HTTP請求。
我通過截圖獲取渲染後的頁面,如下圖:
視訊播放視窗那裡是黑色的,抓包程式抓不到帶有flv字串的HTTP請求。
我還嘗試了1.4.1版本的Phantomjs,網上說可以通過這個命令載入Flash外掛
./bin/phantomjs --load-plugins=yes examples/snap.js
通過渲染JS指令碼,截圖得到下圖:
雖然得到的截圖跟上圖不一樣,視訊那裡多了一個載入的狀態,可是我還是抓取不到視訊HTTP請求。最後,我在python中呼叫
webdriver.Phantomjs()
的時候報錯.
WebDriverException: Message: Can not connect to the Service phantomjs
最後不得不放棄使用Phantomjs
slimerjs
我在網上搜索headless browser時,另外還有搜到slimerjs。
PhantomJS與SlimerJS異同:來自這篇文章
- PhantomJS 基於 Webkit 核心,不支援 Flash 的播放
- SlimerJS 基於火狐的 Gecko 核心,支援 Flash播放,並且執行過程會有頁面展示
正好我們需要支援Flash播放。可是問題又來了!SlimerJS不是一個純正的Headless browser,它需要DISPLAY!!。那麼我們有什麼辦法可以解決這個問題呢?有!
xvfb
xvfb 是通過提供一個類似 X server 守護程序 和 設定程式執行的環境變數 DISPLAY 來提供程式執行的環境
通過這個,也可以解決前面所說到的第一個Firefox遇到的問題了。感覺好像兜了個圈= =!
程式實現
最後我們決定用slimerjs來獲取頁面。因為沒辦法通過python的selenium的方法呼叫slimerjs,那麼我們只能通過python呼叫命令列程式的方法來動態渲染頁面了。slimerjs指令碼如下,我們呼叫這個指令碼的時候,傳入一個網頁地址引數。slimerjs就負責開啟這個頁面,渲染頁面的內容。
這個指令碼的檔名是getPage.js
var page = require('webpage').create();
var videoUrl = phantom.args[0];
var page.open(videoUrl, function (){
window.setTimeout(function(){
phantom.exit();
},10);
});
我們python呼叫os.system("xvfb-run slimerjs getPage.js " + videoURL)
來渲染視訊URL的視訊。
我們最終的python程式是slimerjs_crawl_video.py
import os
import time
open163url = 'http://open.163.com/movie/2016/1/T/D/MBCRLBLRN_MBCRM7OTD.html'
startTime = time.time()
os.system("xvfb-run slimerjs getPage.js " + open163url)
print "use time: " + str(time.time() - startTime)
➜ capture_traffic sudo python pypcap_test.py
[sudo] password for honkee:
starting capture
mov.bn.netease.com/open-movie/nos/flv/2016/01/20/SBCRM4HFN_hd.flv
mov.bn.netease.com/open-movie/nos/flv/2016/01/20/SBCRM4HFN_hd.flv?start=107570066
獲取到視訊地址!!
未解決問題
呼叫python slimerjs_crawl_video.py
時
➜ capture_traffic python slimerjs_craw_video.py
Vector smash protection is enabled.
use time: 94.3547639847
這個時間我還不知道怎麼控制,我試過修改getPage.js
的window.setTimeout
函式的時間,可是這個用時還是90多秒,我猜測是python的os.system()
的限制是阻塞一定時間(90多秒)就返回吧。接下來我再查一查相關的東西。
更新:
今天為了解決這個返回的問題,我開始查詢這個問題的原因,直接找 os.system()
這個函式的文件,它說明這個函式是阻塞的,等待命令執行完成才返回。那麼問題應該就出現在slimerjs的指令碼那裡了,偶然原因,我執行那個指令碼的時候忘了新增視訊網頁路徑引數,結果它很快就返回了。因為我 window.setTimeout()
函式設定的是10毫秒,那麼為什麼我添加了視訊網頁路徑之後就要等待90多秒呢,我打開了firefox的firebug,打開了那個網頁。發現這個函式的時間是在所有請求載入完才開始算的。下圖是firebug截圖。
兩個紅色的請求時到了90秒才表示timeout。這是計時器開始計算,加上程式載入的時間,就是90多秒了。
那麼我們自然就想到將 window.setTimeout()
函式寫在開啟頁面外面,設定時間返回。
getPage.js
var page = require('webpage').create();
var videoUrl = phantom.args[0];
window.setTimeout(function(){
phantom.exit();
},10000);
var page.open(videoUrl, function (){
window.setTimeout(function(){
phantom.exit();
},10);
});
最後發現這個標題不太符合這篇文章。不過還是不改了,因為我本來是按著headless browser的思想去解決這個問題的