怎樣對鏈接進行判重?python
Bloom Filter. 簡單講它仍然是一種hash的方法,可是它的特色是,它可使用固定的內存(不隨url的數量而增加)以O(1)的效率斷定url是否已經在set中。惋惜天下沒有白吃的午飯,它的惟一問題在於,若是這個url不在set中,BF能夠100%肯定這個url沒有看過。可是若是這個url在set中,它會告訴你:這個url應該已經出現過,不過我有2%的不肯定性。注意這裏的不肯定性在你分配的內存足夠大的時候,能夠變得很小不多。一個簡單的教程:Bloom Filters by Examplegit
集羣化抓取
爬取豆瓣的時候,我總共用了100多臺機器晝夜不停地運行了一個月。想象若是隻用一臺機子你就得運行100個月了...那麼,假設你如今有100臺機器能夠用,怎麼用python實現一個分佈式的爬取算法呢?
咱們把這100臺中的99臺運算能力較小的機器叫做slave,另一臺較大的機器叫做master,那麼回顧上面代碼中的url_queue,若是咱們能把這個queue放到這臺master機器上,全部的slave均可以經過網絡跟master聯通,每當一個slave完成下載一個網頁,就向master請求一個新的網頁來抓取。而每次slave新抓到一個網頁,就把這個網頁上全部的連接送到master的queue裏去。一樣,bloom filter也放到master上,可是如今master只發送肯定沒有被訪問過的url給slave。Bloom Filter放到master的內存裏,而被訪問過的url放到運行在master上的Redis裏,這樣保證全部操做都是O(1)。(至少平攤是O(1),Redis的訪問效率見:LINSERT – Redis) 考慮如何用python實現:
在各臺slave上裝好scrapy,那麼各臺機子就變成了一臺有抓取能力的slave,在master上裝好Redis和rq用做分佈式隊列。github
#主、從代碼因而寫成 #slave.py current_url = request_from_master() to_send = [] for next_url in extract_urls(current_url): to_send.append(next_url) store(current_url); send_to_master(to_send) #master.py distributed_queue = DistributedQueue() bf = BloomFilter() initial_pages = "www.renmingribao.com" while(True): if request == 'GET': if distributed_queue.size()>0: send(distributed_queue.get()) else: break elif request == 'POST': bf.put(request.url)
以上簡要示例的具體開源項目:darkrho/scrapy-redis · GitHubredis
展望及後處理
雖然上面用不少「簡單」,可是真正要實現一個商業規模可用的爬蟲並非一件容易的事。上面的代碼用來爬一個總體的網站幾乎沒有太大的問題。可是若是附加上你須要這些後續處理,好比算法
做者:謝科
連接:https://www.zhihu.com/question/20899988/answer/24923424
來源:知乎
著做權歸做者全部,轉載請聯繫做者得到受權。數據庫