爬蟲流程
之前沒了解過相關東西,覺得大體流程無非是發送http request, 然後把爬來的數據進行存儲。
讀了一個相關代碼實現後,往深裏鑽,裏面東西還特別多。核心流程還是一樣,但是考慮到效率就會涉及到很多東西。流程方面可以參考這裏
代碼倉庫
網上誰便找了個,代碼量不大,適合學習使用這裏。
代碼解讀
類圖
- 其中WebSpider 是對外的門面類,其中聚合了抓取線程、解析線程、保存結果線程;還聚合了抓取任務隊列、解析任務隊列、保存任務隊列。
- 其中線程有反過來關聯WebSpider 一次來操作隊列; 線程中有關聯了具體幹活的Worker類。
- Worker泛化具體的抓取、解析、保存操作。裏面自定義具體操作。抓取裏面進行http請求,解析裏面進行正則匹配, 保存進行輸出重定向。
流程圖
維護了三個任務隊列:Fetch, Parser, Saver 分別代表抓取隊列、解析隊列、保存隊列。
初始
- 其中,1、2、3步驟都在各自的線程中運行,初始時會在Fetch Queue 中塞入一個初始url,以此保證後續動作的進行。
- 整個流程由隊列中數據驅動進行,至於線程停止的時機,直到所有任務隊列爲空時,因爲Parser會把解析到的次級url放入Fetch隊列,那麼隊列如何保證可以有爲空的條件呢,這裏Paser幹活類中有個控制抓取url層級的值,當抓取的url層級超過限制的層級後,就不會再往Fetch 隊列中插入了。
關鍵知識
布隆過濾
- python 引入pybloom_live 包來使用。可以理解爲hashmap的替代,但是在數據量巨大時hashmap 會有空間佔用巨大的問題。 但是布隆過濾器也有缺點,他可以告訴“某樣東西一定不存在或者可能存在”,即無法保證確定的存。
- 此程序中在Fetch 獲取到新url後會更新過濾器中值。在數據量小時,看不出布隆過濾的優勢。
Queue
此程序的關鍵代碼理解我覺得主要是queue的使用,剖開具體的操作細節,代碼運行流程可以通過Queue 來看明白。
可以看下面一個生產者–消費者問題,代碼中的queue 的使用是一樣的。
def test_multiply_thread_queue():
num_fetch_threads = 5
enclosure_queue = Queue()
def consumer(i, q):
while True:
print("consumer begin")
url = q.get(block=True)
print('%s: consumer: %s end. %s' % (i, url, time.ctime()))
# time.sleep(1)
q.task_done()
for i in range(num_fetch_threads):
worker = Thread(target=consumer, args=(i, enclosure_queue))
worker.setDaemon(True)
worker.start()
def producer(i, q):
itm = 'url {}'.format(i)
# print('producer: %s begin. %s' % (itm, time.ctime()))
#time.sleep(i)
q.put(itm)
print('producer: %s end. %s' % (itm, time.ctime()))
num_product_threads = 5
for i in range(num_product_threads):
worker = Thread(target=producer, args=(i, enclosure_queue))
worker.setDaemon(True)
worker.start()
# Now wait for the queue to be empty, indicating that we have
# processed all of the downloads.
print('*** Main thread waiting')
enclosure_queue.join()
print('*** Done')
- Queue 自身保證線程安全。這裏join 爲’Blocks until all items in the queue have been gotten and processed.’,等待所有任務被取出, 而後往下執行。這裏join的效果可以通過調整consumer和producer中的sleep看出效果。
- 當生產者執行較快,消費者線程肯定能消費完才結束程序;
當生產者較慢,消費者較快時,生產者可能沒生產幾個就會退出程序,因爲在enclosure_queue.join()時發現隊列爲空,主線程直接往下執行了。