Python爬蟲(以Youtube已授權影片為例)(一)
爬蟲在生活中的應用廣泛,在網路資源豐富的背景時代下,爬蟲算是一個很需要具備的技術。本篇嘗試用一個簡單且完整的例子來講解使用Python爬蟲。
前言
爬蟲這件事情很容易與自動化牽涉到關係,通常在我們希望獲取或更新資料的情況下會想到,尤其在一些重複性的工作,或是設定上相對繁雜(不一定說很難設定,可能就單純只是覺得麻煩),若能夠將整個工作包裝成一個程式,並能夠一鍵自動完成這些工作,甚至讓其自動開始執行工作,真的是方便很多,我們也能夠更專注於在處理其他事情上。
而本系列(由於篇幅會較長,所以以系列作為發布,希望是兩篇結束)將會以Youtube上的已授權影片作為目標,以Python利用爬蟲技術來進行下載,並且會用到FFmpeg來處理影片的相關問題。我想,這樣的一篇文章,能夠提到許多有用的知識與工具,且有一個完整的應用去解決現實中的問題,甚至能更容易去延伸,應該會很有幫助。
本篇主要會提及爬蟲上的概念及相關的準備工作。
爬蟲前的準備
一般我們在正式爬蟲之前,除了去找找看目標網址是什麼,能不能只透過一條網址或API去請求訊息。還會看看有沒有認證與登入機制,要不要設定cookies,也會去注意網站有沒有一些動態的功能,可能需要不斷地刷新狀態才能夠獲取到較全面的訊息。當然,也會去找找有沒有放置一些JavaScript程式碼,以致於某些資料被隱藏起來,或是建立連線時會受到干擾,沒辦法對該網站直接連線。
再來是,會不會有被ban IP的可能性,我們需不需要去等待一段時間才去繼續發送請求連線,到底是固定幾秒鐘呢?或是隨機等待一段時間等等。如果被ban會持續多久的時間?需不需要使用Proxy,像是考慮使用Proxy Pool?
根據這些情況,我們會需要不同的準備工作、手段或使用的工具,以Python上的套件來說,最簡單我們會使用到requests用來連線溝通、urllib中的parse module進行中文、json對JSON格式的文件進行解析、Unicode之間的轉換與解碼、BeautifulSoup來對Html形式等的文件進行解析、selenium來模擬使用者相關的事件,或是考慮Scrapy框架等等。
爬蟲前的心態準備
剛才有提到Ban IP的情況,這類對使用者的追蹤機制很多時候並不是避免使用者或使用者操作bots去跟它請求資料,而是避免其所提供的網路服務因此受影響或是被阻斷,甚至是系統性的崩潰,這樣導致的後果是無法估計的。
而我們作為一個請求者,我們爬蟲是為了向對方拿資料,倒也不是過河拆橋,或是有意要影響對方的服務。因此,我們應該保持一個心態:
我們是擔心對方的服務會因此受到影響,因此有限制並且自律地間斷性,且輕量,慢慢地向對方拿資料,而不是擔心被Ban掉。
說實在的,當我們在考慮使用Proxy服務等等時,本身就是已經在挑戰對方的極限,並承擔服務受影響的風險。
爬蟲應用
而在爬蟲的應用上,通常在網路上會去尋找資源的 Web crawler,我們會叫他們網路蜘蛛(Spider、Spiderbot),最簡單就直接叫做crawler。其中,規模較大的基本上就屬網路檢索器(或稱作漫遊器)了,像是Google、Yahoo、Bing等等的服務或是搜尋引擎都會附帶著這些bots,以Google來說,包含Googlebot、Googlebot-News、AdsBot-Google等等都是。
Google crawler相關清單如下表:
Robots exclusion standard
在提供服務者的角度,雖然其公開相關的網路資源供使用者使用,但仍會希望有一些路徑上的資源不要被過度取用,或是私自隨意利用。因此,有一個標準叫做robots exclusion standard,又稱為robots exclusion protocol,或簡單叫做robots.txt,用來向網路上的crawler宣告允許的清單與禁止的清單等等,也包含應該過多久才能拜訪一次。
通常提供服務者會在網站的根目錄上放置一個robots.txt,來實現這類的標準。那當然,身為使用該服務者的我們,要不要聽就又是另一回事,這回歸到剛剛我們所提到的心態準備。
我們如果要查看該網站的robots.txt,為了避免有些服務是區分字母大小寫(case-sensitive)的,最好統一輸入小寫字母。
以Youtube來說,就是https://www.youtube.com/robots.txt。
然而,這樣的標準,也有一些問題存在,舉例來說,或許服務提供者直接在上面將所有路徑都列為禁止項目,先不管它自己會不會因為搜尋引擎在建立其索引時受到影響,導致它的網站基本上不會出現在搜尋內容中,這樣的行為本身,對網路的生態其實也會有很大的影響,並讓搜尋引擎的功能無法更好的利用。事實上,若不想公開,其實就不公開就行了。
以下我們將開始我們的例子。
操作環境
作業系統: Windows 10
程式語言: Python 3.6.8 64 bits
工具: FFmpeg 4.2.1
版權
我們要向對方請求資源時,包含後續的對該資源的利用,不是單單看過robot.txt文件就好。我們需要對該網站上所發布的條款或聲明進行確認。
像是Youtube的條款
基本上,該服務上所有的東西,除非影片等等資源的擁有者聲明使用者能夠有其他的利用權限,其使用範圍最多就僅限於在該服務,素材用在其他地方基本上是不經過授權的。
因此,接下來的例子,我將只使用自己在Youtube的影片進行爬蟲,避免疑慮,雖然是不公開(若是私人影片,則需要使用帳號登入)的,但這不影響整個爬蟲的流程。因此,各位如果要嘗試,不管在哪個平台或網路服務,盡量在確定自己有授權的情況下,去嘗試這類的動作。
檢查目標位置
首先,我們得先決定需要哪些資訊,以及這些資訊的所在位置。
因為我們只是需要下載影片,所以我們僅僅需要取得該影片標題以及影片的下載連結就行。
一般我們會搭配瀏覽器上的開發人員工具,以Chrome來說,我們可以透過快捷鍵F12或是Ctrl + Shift + I,亦或是透過滑鼠右鍵=>選單上的"檢查"來開啟。
所以我們透過瀏覽器打開目標的影片,並且打開開發人員工具的Elements分頁頁面。是意圖如下:
由於Youtube平台上的影片會有播放品質的選項,因此,不同品質的影片應該各自會有一組對應的參數與一個URL,不太可能當下進行影像處理對吧。
由於這類的操作是一個動態的,基本上會是由JavaScript程式碼去進行決定與控制,順利的話,資料可能就直接藏在JavaScript程式碼當中。事實上,確實是如此。
一般我們可能會透過開發人員工具的選擇元素功能,來對網頁頁面上的元素進行選擇,搭配當前原始碼與參數(在開發人員工具的Elements分頁中),就會自動帶到該元素的程式碼區塊。
但我們看到的連結卻是一個blob:開頭的URL,這類的URL會連結到一個包含Blob(Binary Large Object)物件的陣列,這個物件通常被用來存放原始的檔案資料。我們可以透過JavaScript來建立Blob物件、建立含Blob物件的URL以及擷取Blob物件資料。
但這不是我們想要的目標網址,而就像是剛才所說,我們的目標其實就藏在JavaScript程式碼當中。我們回過頭來看看剛才的圖:
其中,有一個JavaScript程式碼片段,有宣告了一個變數,裡面存放著一系列的資訊,當中就有好幾組資料,會有不同的Quality、MIME type、URL等等。
Youtube通常將影片拆分成影片檔與聲音檔,我們如果特別去查看開發人員工具中的Network分頁,找到包含videoplayback字眼的連結就能看出。而在該連結的Response分頁,我們可以看到主要都是ASCII碼(American Standard Code for Information Interchange,美國資訊交換標準代碼),一般我們沒辦法直接看懂裡面的內容,這個是影音檔很顯著的特徵。
而剛才有提到MIME type,MIME type又稱為網際網路媒體類型(Internet media type)、MIME類型以及內容類型(Content type),主要用於對網路傳輸的檔案與內容進行分類。有這項資訊的話,我們可以更容易地找出影片檔以及聲音檔。
在Youtube影片中,MIME type通常分為audio/mp4、audio/webm、video/mp4、video/webm等等。
接著搭配影片的品質(Quality)資訊,最終,我們可以確定哪幾條是我們所要下載的目標。
品質的部分,影片分為144p、240p、360p、480p、720p、1080p等等;聲音檔則是AUDIO_QUALITY_LOW、AUDIO_QUALITY_MEDIUM等等,我目前倒是還沒看過AUDIO_QUALITY_HIGH,但應該是有。
影片的標題的話,有很多個地方都能取得,但為了方便處理,我們需要一個能夠唯一進行區分的方式,畢竟如果該頁面中有許多個標題,其前後的特徵都長得一樣,那就很不方便定位了是吧?
正好當前的影片標題這項資訊在JavaScript程式碼中也能找出來,在開發人員工具中的Elements分頁中,透過Ctrl + F進行搜尋"title":"就能夠找到唯一的一個關鍵字串,後面就附帶有我們要的影片標題。
那到目前為止,我們所需要的準備工作都準備好了。
結論
本篇主要介紹到了爬蟲,包含相關的應用與知識,而為了有一個較完整的例子,我們舉了個下載Youtube已授權影片的例子,並初步對我們要爬蟲的目標進行了解析,確定爬蟲方向。而在下一篇,才會開始提及使用Python爬蟲的部分,以及使用FFmpeg這項工具進行影片檔與聲音檔的合併。