用 python 寫的爬蟲,有哪些提高的技能?

背景說明:我初學python爬蟲,要爬國內某網站上的數據做數據分析用,數據總共大約有 15e6 條,在這個網站上每個頁面有 15 條數據。也就是說大約有 1e6 的頁面要爬取。
目前爬取方案:獲取html頁面後用正則表達式匹配。在把匹配後的插入資料庫中。我開了3個線程,分別從 0 , 1/3 ,2/3 出開始爬取。開多線程雖然有常數的優化,但是本身基數就很大,優化很不明顯。
現在想學習解決的問題:
1,能否通過學習一些新的技術獲得一個較大的優化?
2,在前期爬取的過程中速度明顯比現在快,隨著資料庫里內容的增加,插入一條數據花費的時間邊的更多了。(ps:資料庫用的 sqlite3)(程序在新建資料庫時運行速度會有較大提升,但資料庫一旦到達 300 M 左右時耗時會明顯增加)。資料庫方面能有什麼樣的優化。
3,最近在學《計算機網路》,老師在課上講到了分散式應用。想學著寫個分散式的爬蟲,就算是自己的練習。知友有哪些好的項目可以推薦一下學習?


那些給你安利什麼gevent/xpath什麼的人,一定沒有寫過爬千萬級或者億級以上數據量的爬蟲。

按照你的需求,你有1500萬條數據需要抓取,這1500萬條數據分布在100萬頁網頁中。那麼,從以下幾個方面給題主一點建議。

首先,存儲的問題,爬蟲的數據,尤其到了一個比較大的兩極,sqlite3這種文件型的資料庫最好不要用了,建議使用MongoDB做存儲,簡單實用,方便拓展爬蟲的數據。

其次,如果可以,將這100萬頁頁碼分解成100萬個任務,放到一個MessageQueue中。

接著,在寫程序的時候,不要考慮任何多線程多進程gevent或者任何會讓你的程序「提速」的東西,你的爬蟲只要完成一個簡單的功能:接受一個輸入,這裡就是某一頁的頁碼,得到的輸出是這一頁的15條數據,最好直接存儲到資料庫中。

最後一步,將上兩步具體實現,建議使用RabbitMQ或者ActiveMQ,然後在上一步的接受輸入變成從Queue中取一條任務。如果源網站不會因為訪問頻率過高而封你的IP,那麼你可以在一台機器上多部幾個爬蟲實例,否則的話,你可以將你的代碼部署到多台機器上。阿里雲按時間付費的機器很便宜,你可以開多點機器以加快速度。

這樣的好處是,你可以隨時新增或減少一個爬蟲實例,而不會影響之前已經部署的任何爬蟲,也可以隨時將抓取失敗的頁碼數再次放入Queue中,而不影響正在抓取任務的爬蟲。

最後,如果你按照這樣的思路完成,你只需要寫爬蟲和搭建MessageQueue,它們之間的交互已經有了現成的庫xtls可以幫你:
pypi: https://pypi.python.org/pypi/xtls/
文檔:xtls: awesome tools by xlzd
github:xlzd/xtls · GitHub


任務入MessageQueue:

from xtls.activemqwraps import producer

# mq_uri 是你的MQ的連接地址
# queue_name 是queue的名字

@producer(mq_uri, queue_name)
def insert_task():
# 你有一百萬個頁碼的任務
# 如果你的任務是其它複雜的內容,也可以yield出去
# 會自動加入到MessageQueue中
for page in xrange(1, 1000001):
yield page

爬蟲端取出任務:

from xtls.activemqwraps import consumer

# mq_uri 是你的MQ的連接地址
# queue_name 是queue的名字
# param_type 是你入庫時yield出去的對象的類型,對應的你task接受的param的類型

@consumer(mq_uri, queue_name, param_type=str)
def task(param):
pass # crawl target


針對題目,我有兩個建議:
1. 使用xpath或者css selector替代正則。
2. 使用gevent來提升爬取速度。

感謝 @松鼠奧利奧 提到我,發現當初回答這道題是用手機隨手一答,並沒有說清楚具體原因,抱歉。

為什麼建議使用xpath代替正則?
對於固定場景,合適的正則表達式解析的效率是會高於xpath的,之所以提倡使用xpath,是因為程序可維護性,xpath的可讀性遠高於正則表達式,開發調試和維護效率會大大提高。

為什麼建議使用gevent?
爬蟲程序明顯是IO密集型的程序,使用gevent可以使得阻塞的IO操作變成非阻塞,減少無謂的等待時間,從而提高效率。
所有性能問題都能通過堆硬體的方式來解決,我們現在討論的是如何最大效率地利用硬體。
利用消息隊列來進行調度是個很聰明的方案,但是如果我們發現消息隊列中的消息是有堆積的,那麼說明這個系統真正的瓶頸並不在於消息隊列,而在於爬取端。
我們可以通過簡單地啟動多個爬取實例消費同一個消息隊列的任務來提升爬取速度,但是要注意,在一個系統中啟動過多的爬取實例,進程切換的開銷反而會使得效率下降,實例個數一般推薦為cpu的核數。
我的觀點是,爬取實例儘可能高效,而爬取頻率應該是調度方來控制,同時多機同時爬取也是很好的。


Scrapy,mongdb,如果要用搞個分散式的話再加個redis


爬蟲看看scrapy即可,都幫你想好了。性能問題不用想太多,主要是看你有多少台機器和你的帶寬。

資料庫有很多方法。例如可以先寫文件或key-value型資料庫,再弄個腳本存入做數據分析用的資料庫。


安利scrapy
這個框架比你自己擼快太多了

300mb卡了…
sqlite開一次關一次延遲挺大的
你有啥變數沒清空?
還是你往sqlite裡面存了奇怪的東西…
我瞎猜的

哦小心被ban 假期爬tripadvisor 爬到第八個小時被block… 當時想掀桌…


如果用十幾台爬蟲機抓數據,應該兩三天就可以爬完了,一台機器的話,時間會長一點。幾點建議:
1,線程開的多一些,比如50個線程或者一百個線程,具體可以top一下看看負載怎麼樣來決定線程數。
2,如果是分散式,一台master多台slave,master用來調度爬蟲任務,消息隊列可以用redis,每台slave機器使用多線程。
3,建立一個ip池,每個ip隔一段時間爬取,這樣防止被封,ip池可以上網去找,然後做一下驗證,看是否可用。
4,如果需要,學一下模擬登陸。
5,不建議用sqlite,甚至可以不用資料庫,可以直接寫到txt裡面存下來,等到計算的時候也很方便處理。
6,xpath解析用lxml,不規則的網頁用正則匹配。


你說的輪子scrapy都幫你做好了
scrapy/scrapy · GitHub
存儲搞個NoSQL吧


xlzd說的是對的。
爬蟲首先要做成分散式。用queque來做。
程序的大部分時間都花在下載上,你用同步還是非同步寫完全沒區別。
別用多線程爬,分分鐘被封掉。必要的時候還要加時延。
每個子任務爬之前,url過一遍bloom filter,資料庫查一遍,確保不做重複下載。
資料庫用mongo,index做好,不然到幾百萬後會很慢。
還有就是不要迷信scrapy,很多時候自己寫的更好用。


推薦閱讀:

學校圖書館購買的資料庫是什麼?
(文獻搜索大神進)跪求!!求外國免費的資料庫鏈接。能找到英文圖書和英語期刊論文,能全文查看論文的那種?
約 1億條記錄, 每條1k左右,key =>value形式,用於前台查詢,選擇什麼作為存儲方案比較合適呢,要求效率比較高並且相對穩定可靠?
資料庫的選擇?
SQLite 的讀寫效率很高,有哪些使用其他資料庫的理由?

TAG:資料庫 | Python | 計算機網路 | 爬蟲計算機網路 | 分散式 |