1、什麼是爬蟲?python
網絡爬蟲(又被稱爲網頁蜘蛛,網絡機器人,在FOAF社區中間,更常常的稱爲網頁追逐者),是一種按照必定的規則,自動的抓取萬維網信息的程序或者腳本。git
1)你須要學習github
import Queue initial_page = "http://www.renminribao.com" url_queue = Queue.Queue() seen = set() seen.insert(initial_page) url_queue.put(initial_page) while(True): #一直進行直到海枯石爛 if url_queue.size()>0: current_url = url_queue.get() #拿出隊例中第一個的url store(current_url) #把這個url表明的網頁存儲好 for next_url in extract_urls(current_url): #提取把這個url裏鏈向的url if next_url not in seen: seen.put(next_url) url_queue.put(next_url) else: break
2)效率redis
設想全網有N個網站,那麼分析一下判重的複雜度就是N*log(N),由於全部網頁要遍歷一次,而每次判重用set的話須要log(N)的複雜度。OK,OK,我知道python的set實現是hash——不過這樣仍是太慢了,至少內存使用效率不高。算法
一般的判重作法是怎樣呢?Bloom Filter. 簡單講它仍然是一種hash的方法,可是它的特色是,它可使用固定的內存(不隨url的數量而增加)以O(1)的效率斷定url是否已經在set中。惋惜天下沒有白吃的午飯,它的惟一問題在於,若是這個url不在set中,BF能夠100%肯定這個url沒有看過。可是若是這個url在set中,它會告訴你:這個url應該已經出現過,不過我有2%的不肯定性。注意這裏的不肯定性在你分配的內存足夠大的時候,能夠變得很小不多。一個簡單的教程:Bloom Filters by Example數據庫
3)集羣化抓取json
那麼,假設你如今有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用做分佈式隊列。app
代碼因而寫成dom
#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 · GitHub
可是若是附加上你須要這些後續處理,好比
爬取知乎頭像的代碼(暫時沒有弄懂,運行不出來,等稍後再考慮)
做者:挖數 連接:https://www.zhihu.com/question/20899988/answer/96904827 來源:知乎 著做權歸做者全部,轉載請聯繫做者得到受權。 import requests import urllib import re import random from time import sleep def main(): url='知乎 - 與世界分享你的知識、經驗和看法' #感受這個話題下面美女多 headers={省略} i=1 for x in xrange(20,3600,20): data={'start':'0', 'offset':str(x), '_xsrf':'a128464ef225a69348cef94c38f4e428'} #知乎用offset控制加載的個數,每次響應加載20 content=requests.post(url,headers=headers,data=data,timeout=10).text #用post提交form data imgs=re.findall('<img src=\\\\\"(.*?)_m.jpg',content) #在爬下來的json上用正則提取圖片地址,去掉_m爲大圖 for img in imgs: try: img=img.replace('\\','') #去掉\字符這個干擾成分 pic=img+'.jpg' path='d:\\bs4\\zhihu\\jpg\\'+str(i)+'.jpg' #聲明存儲地址及圖片名稱 urllib.urlretrieve(pic,path) #下載圖片 print u'下載了第'+str(i)+u'張圖片' i+=1 sleep(random.uniform(0.5,1)) #睡眠函數用於防止爬取過快被封IP except: print u'抓漏1張' pass sleep(random.uniform(0.5,1)) if __name__=='__main__': main()
做者:謝科 連接:https://www.zhihu.com/question/20899988/answer/24923424 來源:知乎 著做權歸做者全部,轉載請聯繫做者得到受權。