Python爬蟲綜述(筆記)

1、什麼是爬蟲?python

網絡爬蟲(又被稱爲網頁蜘蛛,網絡機器人,在FOAF社區中間,更常常的稱爲網頁追逐者),是一種按照必定的規則,自動的抓取萬維網信息的程序或者腳本。git

1)你須要學習github

  1. 基本的爬蟲工做原理
  2. 基本的http抓取工具,scrapy
  3. Bloom Filter: Bloom Filters by Example
  4. 若是須要大規模網頁抓取,你須要學習分佈式爬蟲的概念。其實沒那麼玄乎,你只要學會怎樣維護一個全部集羣機器可以有效分享的分佈式隊列就好。最簡單的實現是python-rq: https://github.com/nvie/rq
  5. rq和Scrapy的結合:darkrho/scrapy-redis · GitHub
  6. 後續處理,網頁析取(grangier/python-goose · GitHub),存儲(Mongodb)
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

 

可是若是附加上你須要這些後續處理,好比

  1. 有效地存儲(數據庫應該怎樣安排)
  2. 有效地判重(這裏指網頁判重,咱可不想把人民日報和抄襲它的大民日報都爬一遍)
  3. 有效地信息抽取(好比怎麼樣抽取出網頁上全部的地址抽取出來,「朝陽區奮進路中華道」),搜索引擎一般不須要存儲全部的信息,好比圖片我存來幹嗎...
  4. 及時更新(預測這個網頁多久會更新一次)

爬取知乎頭像的代碼(暫時沒有弄懂,運行不出來,等稍後再考慮)

做者:挖數
連接: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 來源:知乎 著做權歸做者全部,轉載請聯繫做者得到受權。

相關文章
相關標籤/搜索