大連理工大學城市學院 唐 琳 董依萌 何天宇
隨著網(wǎng)絡的不斷發(fā)展,大量數(shù)據(jù)以文本形式、圖片甚至視頻的形式存儲,通過網(wǎng)絡爬蟲(Crawler)獲取網(wǎng)絡數(shù)據(jù)是一種非常流行的方法。本文將基于Python的網(wǎng)絡爬蟲技術的關鍵性問題以及一些相應的解決方法進行討論。
數(shù)據(jù)爬取任務通常是基于Robots協(xié)議進行,再分析網(wǎng)站DOM樹爬取所需要的數(shù)據(jù)。在解析過程中主要使用正則表達式進行篩選和匹配,針對網(wǎng)站的反爬取機制采取一些措施和手段。下面分別針對這些具體知識點和解決方案進行介紹:
Robots協(xié)議的全稱是網(wǎng)絡爬蟲排除標準(即Robots Exclusion Protocol),網(wǎng)站通過Robots協(xié)議告訴搜索引擎哪些頁面可以抓取,哪些頁面不能抓取。它是Web站點和搜索引擎爬蟲交互的一種方式,并不是一個規(guī)范,所以并不能保證網(wǎng)站隱私。在互聯(lián)網(wǎng)世界中,每天都有不計其數(shù)的爬蟲在日夜不息地爬取數(shù)據(jù),其中惡意爬蟲的數(shù)量甚至高于非惡意爬蟲。遵守Robots協(xié)議的爬蟲才是好爬蟲,但是并不是每個爬蟲都會主動遵守Robots協(xié)議。
網(wǎng)站結(jié)構分析是進行數(shù)據(jù)采集的必備技能,在編寫爬蟲之前我們需要知道數(shù)據(jù)所在的位置,之后才能通過遍歷節(jié)點樹或查找子節(jié)點找到目標數(shù)據(jù)。Google瀏覽器的開發(fā)者模式就是分析網(wǎng)站結(jié)構的強力工具,利用好這個工具就可以輕松分析出目標數(shù)據(jù)的位置,還能獲取渲染內(nèi)容、cookies等信息。
正則表達式是一種基于規(guī)則進行字符串匹配的工具,不同編程語言都有正則表達式使用的場景。通常我們利用正則表達式從復雜的內(nèi)容種,提取出我們想要的部分內(nèi)容。
動態(tài)的網(wǎng)站由于不能直接獲得想要數(shù)據(jù),需要得到渲染之后的網(wǎng)頁等內(nèi)容加載完成之后在進行下載。其中,模擬翻頁可以使用Selenium與PhantomJS模擬瀏覽器方法實現(xiàn),具體實現(xiàn)就是通過模擬鼠標點擊頁碼請求后臺,獲取到新數(shù)據(jù)后重新渲染html的表格部分。
某些網(wǎng)頁具有反爬取機制,為了不讓爬蟲爬取數(shù)據(jù),有些時候會檢查瀏覽器頭Request Header,然后直接斷網(wǎng)從而拒絕爬取。一個很好的方法就是在Google瀏覽器開發(fā)者模式中Network查看生成的請求html文件獲取Request Headers,再通過Google工具Postman轉(zhuǎn)換為Python代碼。
在爬取網(wǎng)站信息的過程中,網(wǎng)站可能會限制每個IP的訪問速度或訪問次數(shù)。對于限制訪問速度的情況,通過time.sleep使程序進行短暫休眠后再發(fā)出請求進行爬取。對于限制IP訪問次數(shù)的時候我們需要通過多個代理IP構建代理IP池輪換訪問。
多線程與多進程都能成倍的提高爬蟲的速度,進程的問題是不同進程之間的內(nèi)存空間不共享,進程之間的通信有操作系統(tǒng)傳遞,導致通訊效率低,切換開銷大。而所有線程在同一個進程下,共享內(nèi)存空間,通訊效率高,切換開銷小。線程為了保護內(nèi)存空間的數(shù)據(jù)安全,引入了”互斥鎖”。線程的問題是在Python里由于GIL全局解釋器鎖的存在,一個線程需要執(zhí)行任務必須獲取GIL,在Python的進程里只有一個GIL,但是,在I/O阻塞的時候,解釋器會釋放GIL。所以密集CPU任務,需要充分使用多核CPU資源(服務器,大量的并行計算)的時候,用多進程。密集I/O任務(網(wǎng)絡I/O,磁盤I/O,數(shù)據(jù)庫I/O)使用多線程合適。根據(jù)爬蟲自身檢索頁面(I/O)的行為比較多,還是分析頁面(CPU)的行為更復雜來選擇使用多線程與多進程就好了。
在爬蟲開始之前,首先需要我們掌握一些HTML5的基本知識。可以通過在網(wǎng)上或者查閱一些書籍來學習它。可以看懂頁面的源代碼,掌握頁面源代碼的基本結(jié)構和可以找到想要元素所在的標簽位置。然后在python 2.x中可以通過pip install beautifulsoup4來安裝beautifulsoup4庫和pip install requests來安裝requests庫。python 3.x可以通過pip3 install beautifulsoup4來安裝beautifulsoup4庫和pip3 install requests來安裝requests庫。然后學習requests庫和BeautifulSoup4庫的使用。
Python中正則表達式需通過import re來導入re庫來使用。程序種最為常用的功能函數(shù)。搜索字符串,以列表類型返回全部能匹配的子串的findall();在一個字符串中替換所有匹配正則表達式的子串,返回替換之后的字符串sub();將一個字符串按照正則表達式匹配結(jié)果進行分割,返回列表類型split()等。
爬取動態(tài)網(wǎng)站數(shù)據(jù)還需要使用模擬瀏覽器。一般客戶端常見的瀏覽器需要渲染出圖形,因此執(zhí)行效率較慢。如chrome、firefox。另一種瀏覽器沒有GUI界面,被稱為無頭瀏覽器,這類瀏覽器占用的空間少,執(zhí)行效率高。如PhantomJS。適合linux這種純CLI界面服務器來執(zhí)行,所以在爬蟲程序中,如果是需要使用模擬瀏覽器則需要使用無GUI的瀏覽器。
網(wǎng)絡中數(shù)據(jù)較多時通常分頁存儲,因此,爬蟲代碼中敬仰需要實現(xiàn)翻頁功能。常見翻頁的實現(xiàn)主要有兩種方法。第一種方法是在每次點擊下一頁按鈕的時候,可以看到對應頁面的url是在不停變化的,也就是靜態(tài)的生成了一個新的頁面,并且可以看到每次生成的新的頁面的url是有規(guī)律可循的。那么我們就可以根據(jù)這一情況,在編寫代碼的循環(huán)里面實現(xiàn)對url的不停更新,也就實現(xiàn)了翻頁的功能。第二種方法就是,每次在點擊下一頁的時候,當前頁面的url并沒有變化,變化的是這個頁面的內(nèi)容。也就是在點擊下一頁的時候這個網(wǎng)頁動態(tài)的加載了新的內(nèi)容。這就意味在每次翻頁的時候都需要人為的去點擊下一頁按鈕。為了解決這一問題就有了模擬瀏覽器,讓這個模擬瀏覽器去模擬人為點擊下一頁按鈕的動作,實現(xiàn)翻頁的功能,然后就可以繼續(xù)去分析獲取頁面的內(nèi)容,并得到需要的內(nèi)容。
還有有一些網(wǎng)頁是隱含分頁形式顯示的,即在顯示的時候只顯示一部分,只有在鼠標向下滾動的時候才會繼續(xù)顯示,這樣的話就存在爬蟲爬取下來一個不完整的內(nèi)容,那么我們就可以讓這個模擬瀏覽器來模擬這個動作,從而可以獲得完整的頁面內(nèi)容。
對于一些網(wǎng)站,如果不是從瀏覽器發(fā)出的請求,則得不到響應。所以,我們需要將爬蟲程序發(fā)出的請求偽裝成瀏覽器發(fā)出的正常請求。具體實現(xiàn):自定義網(wǎng)頁請求報頭打開工具Fiddler,然后再瀏覽器訪問一個url,在Fiddler左側(cè)訪問記錄中,找到“200 HTTPS url”這一條,點擊查看其對應的請求和響應報頭具體內(nèi)容。然后在自己的爬蟲代碼中加入這些內(nèi)容。
(1)多線程適合IO密集型程序
IO密集型代碼(文件處理、網(wǎng)絡爬蟲等),多線程能夠有效提升效率(單線程下有IO操作會進行IO等待,造成不必要的時間浪費,而開啟多線程能在線程A等待時,自動切換到線程B,可以不浪費CPU的資源,從而能提升程序執(zhí)行效率)。所以python的多線程對IO密集型代碼比較友好。當我們使用多線程爬取時,會出現(xiàn)爬蟲每次都會把url列表里url在沒有爬取內(nèi)容的時候就已經(jīng)生成了一個線程,就會出現(xiàn)如果斷網(wǎng)的話,就會有很多的url其實還沒有被爬取,對存儲文件的處理就變得很麻煩。對于任務數(shù)量不斷增加的程序來說,每有一個任務就要為這些新的鏈接生成新的線程,線程數(shù)量暴漲,最終線程數(shù)量就會失控。在之后的運行中,線程數(shù)量還會不停的增加,完全無法控制。所以,對于任務數(shù)量不端增加的程序,固定線程數(shù)量的線程池是必要的。
(2)多進程適合CPU密集運算型程序
因為每個進程都有單獨的GIL,互不干擾,這樣就可以實現(xiàn)真正意義上的并行執(zhí)行,所以在python中,多進程的執(zhí)行效率優(yōu)于多線程(僅僅針對多核CPU而言)。在多核下,如果想做并行執(zhí)行提升程序效率,比較常用有效的方法是使用多進程。
創(chuàng)建一個進程池,進程個數(shù)為cpu內(nèi)核數(shù)。電腦的cpu有多少內(nèi)核便可以同時執(zhí)行多少個進程,當然也可以填的很多,但是作用不大,并不是進程數(shù)越多程序執(zhí)行就會越快。
通過以上對基于python的網(wǎng)絡爬蟲的關鍵性問題的結(jié)束和解決,可以看到在網(wǎng)絡飛速發(fā)展,信息傳播快速的現(xiàn)在,可以知道網(wǎng)絡爬蟲是我們大量獲取網(wǎng)絡數(shù)據(jù)的主要手段。為了學好這一技術,首先我們要學會HTML5,通過一些書籍和反反復復查看一個網(wǎng)頁的源代碼結(jié)合來學習這門語言,掌握它的基本語法和結(jié)構。學會使用F12:快捷鍵,(更多工具——開發(fā)者工具)。接下來就要學會bs4和re結(jié)合使用,bs4可以找到需要的標簽,re可以從這個標簽中獲得需要的內(nèi)容,從而可以在頁面中解析和獲得我們想要的內(nèi)容。在學習一個模擬瀏覽器,實現(xiàn)翻頁和加載完畢頁面內(nèi)容,這樣一個簡單的爬蟲就實現(xiàn)了??梢岳^續(xù)改進代碼結(jié)合數(shù)據(jù)庫來實現(xiàn)一個簡單的網(wǎng)頁去重,偽裝一下爬蟲的首部,以及通過多線程或者多進程來提高爬蟲的效率。最后要注意爬蟲的時效性,作為一個網(wǎng)絡爬蟲開發(fā)者,我們應該隨時關注我們正在爬取的網(wǎng)站的網(wǎng)頁的結(jié)構,一旦發(fā)生了變化,我們就要及時更新爬蟲的解析規(guī)則,以確保爬蟲的正常運行。