(from http://chentingpc.me/article/?id=961)
事情的起因是,我做survey的時候搜到了這兩本書:Computational Social Network Analysis和Computational Social Network,感覺都蠻不錯的,想下載下來看看,但是點開網頁發現這個只能分章節下載,暈,我可沒時間一章一章下載,想起了迅雷的下載全部鏈接,試試看,果真可以把他們一網打盡,但是,sadly,迅雷下載的時候,文件名沒辦法跟章節名對應起來,暈,我可沒時間一章一章去改名字,怎么辦呢?由於做過網站,我看着它那“整潔”的頁面就笑了,因為這種規整的頁面是有規律可循的,雖然下載PDF的每個鏈接都含有用HASH隨機生成的數字碼,但是HTML+CSS的排版是規整的,就可以用正則等方法來把title和PDF都挖出來並且一一對應上。想到下一步是要用到網頁分析、抓取、下載的技術的,所以,今天就把這個技術給拿下吧。由於python似乎是我知道的這方面的“利器”,有比較好的原生和社區支持,簡單明了以及良好的跨平台性,所以就用python來做這個工作了。
S1.目標
- 抓取一個網頁並分析,從而:
- 得到半結構化數據,如抓取新浪微博一個頁面中的內容。
- 得到其他網頁的指針,如抓取新浪微博中下一個頁面。
- 下載文件,如這次要下載PDF的任務。
- 多線程抓取與分布式抓取。
- 自動密鑰破解。
S2.方法概述
有多少種方法可以用的呢?
1.自己寫
urllib2+urlparse+re
最原始的辦法,其中urllib2是python的web庫、urlparse能處理url、re是正則庫,這種方法寫起來比較繁瑣,但也比較“實在”,具體可以參考[4].
urllib2+beautifulsoup
這里的得力干將是beautifulsoup[5],beautifulsoup可以非常有效的解析HTML頁面,就可以免去自己用re去寫繁瑣的正則等。我比較喜歡這種方法,在下面具體講解部分會詳解。
Mechanize+BeautifulSoup
Mechanize是對於urllib2的部分功能的替換,使得除了http以外其他任何連接也都能被打開,也更加動態可配置,具體參考[6].
PycURL,據說速度非常快,具體方法可以參考[1][2].
2.公開庫
Scrapy
這個暫且未嘗試,這種公開的庫的有點應該就是速度快、更強大,好像是可以並行的,所以以后有時間再嘗試下。
其他更多的開源庫參考[3].
S3.具體講解
假設你已經把python安裝好了(我用的版本是python2.7),現在我們用urllib2+BeautifulSoup的方法來抓取springerlink網站上的Computational Social Network Analysis和Computational Social Network,也就是上面提到的,這兩本書。
BeautifulSoup的安裝,我是在Windows下安裝的,官網上沒有window下安裝的教程,我是憑感覺裝上的。它有一個setup.py,我就用"python.exe setup.py install"運行了,但提示"error: package directory 'bs4' does not exist",原來是默認python執行路徑不在當前目錄,而是在C盤下面的用戶目錄中,所以把bs4文件移動過去就好了。跑完好,生成一個build文件夾,我知道它肯定要放到Python文件下的LIB文件夾里面去,所以就把下面的bs4移到LIB中去,就可以了。以后要用,直接import即可。如果是linux用戶裝起來應該會更順利些。
用urllib2抓取網頁/下載文件,urllib中最關鍵的可能就是urlopen這個函數了,返回的就是這個webpage/文件對象,可以用read等方法將其讀出來。urlopen這個函數的參數可以是url也可以是Request,如下:
req = urllib2.Request(url, headers={'User-Agent' : "Magic Browser"})
webpage= urllib2.urlopen(req)
webpage.read()...
這里要注意的一點是headers={‘User-Agent’:'Magic Browser'},這個最好加上,否則的話,由於內部信息默認顯示為機器代理,可能被服務器403 Forbidden拒絕訪問,在抓取springelink.com上數據的時候不加上一定會被403斃掉的。
用BeautifulSoup處理解析網頁,import后,一切從soup = BeautifulSoup(webpage.read( ))開始,你可以用python的終端自己玩玩這個產生的soup對象。我這里就說下一種我比較喜歡的用法,詳細具體的API參考[9].我喜歡用嵌套的方式來提取內容,什么意思呢,其實我認為大多數解析定位問題,其實就是下面這樣一個問題:
假設有一個頁面如下:
並且你已經用soup = BeautifulSoup()初始過了,現在你要根據<div id="a"> -> <div class='aa'> -> <p>這樣的結構把下面所有的鏈接抽取出來,怎么做呢?比較簡單的做法,就是一層一層向下分析,具體如下:
top_div = soup.find('div', {'id':'a'}) #注意:返回的是list對象
aa_div = top_div.findAll('div', {'class':'aa'}) #同樣是list對象
links = [div.findAll('a') for div in aa_div] #還是list對象
links[0].get('href') ##
links[0].contents #ff
除了鏈接以外,其他內容也是通過類似的方法解析得到。(PS,我發現我若干個小時前自己還沒解決這個問題的時候在SO上發的一個問題已經有人回答了,真好,那時候其實是困在了對list對象直接用find_all出錯)
S4.Ending
好吧,最后看看我們的戰利品:
聲明1,其實有一個2M多的文件下載失敗了,今天網絡確實有點慢,其實用chrome下載它也差點失敗了,因此,其實還是有可改進的地方。當然,可改進地方多了,多線程啥的,暫不討論了。
聲明2,由於是用T學校的網來下的,並且沒有復制擴散內容,所以沒有侵權!
最后感嘆下,最近多以看論文為主,好久沒學“技術”了,今天用了一些時間搞搞這種敏捷學習,重新體驗那種多線程、開N個窗口、各種任務並發的感覺,真舒服,哈哈:-D
Reference
[2] http://pycurl.sourceforge.net/
[3] http://en.wikipedia.org/wiki/Web_crawler#Open-source_crawlers
[4] http://ryanmerl.com/2009/02/14/python-web-crawler-in-less-than-50-lines/
[5] http://www.crummy.com/software/BeautifulSoup/
[6] http://wwwsearch.sourceforge.net/mechanize/
[8] https://github.com/scrapy/dirbot
[9] http://www.crummy.com/software/BeautifulSoup/bs4/doc/
源代碼下載:code