python爬蟲 | 帶你入門布式程序爬蟲
本文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯絡我們以作處理
以下文章來源於騰訊雲 作者:使用者2769421
( 想要學習Python?Python學習交流群:1039649593,滿足你的需求,資料都已經上傳群檔案流,可以自行下載!還有海量最新2020python學習資料。 )
1.預備知識
今天咱們來扯一扯分散式程序爬蟲,對爬蟲有所瞭解的都知道分散式爬蟲這個東東,今天我們來搞懂一下分散式這個概念,從字面上看就是分開來佈置,確實如此它是可以分開來運作的。
分散式程序就是將程序分佈到多臺機器上去,充分利用每一臺機器來完成我們的爬蟲任務。分散式程序需要用到multiprocessing模板,multiprocessing模板不但支援多程序,它的managers子模組還支援把多程序分佈到多臺機器上。
我們可以寫一個服務程序作為排程者,然後將我們的爬蟲任務分佈給其他的多個程序當中去,我們依靠網路通訊來管理這些程序。
”
2.模擬一個分散式程序爬蟲
我們來模擬進行一個分散式程序的爬蟲吧,就比如我們需要抓取某個圖片網站的所有圖片,如果用我們的分散式程序的思想,我們會建立一個程序負責抓取圖片的連結地址,然後將這些連結地址存放到Queue中,另外的程序負責從Queue中讀取連結進行圖片的下載或者進行其他操作(存在本地).
其實我們的Queue是暴露在網路中的,通過分散式就是將其進行了封裝,其實也就是所謂的本地佇列的網路化。
接下來,我們來分析一下如何去建立一個分散式的服務程序,總體可以分為六步:
- 首先我們需要建立一個佇列queue,這個主要用作程序之間的通訊。總體來說就是兩種程序,一種是服務程序,一種是任務程序。服務程序建立任務佇列task_queue,用作傳遞任務給任務程序的通道。服務程序又建立result_queue,作為任務程序完成任務後回覆服務程序的通道。在分散式程序的環境下,我們需要通過Queuemanager 獲得的Queue介面來新增任務。
- 把我們在第一步中佇列在網路上進行註冊,暴露給其他的程序或者主機,註冊後獲得網路佇列,相當於本地佇列的映像。
- 建立Queuemanager的物件,並且例項化,繫結埠和口令
- 啟動第三步中建立的例項,即啟動管理manager,監管資訊通道
- 通過管理例項的方法獲取到通過網路訪問的queue物件,也就是把網路物件實體化成本地的一個佇列。
- 建立任務到“本地”佇列中,自動上傳任務到網路佇列中,分配給任務程序進行處理。
我們就來寫一下服務程序的程式碼 taskManager.py:
import queue from multiprocessing.managers import BaseManager from multiprocessing import freeze_support # 任務個數 task_num = 500 # 定義收發佇列 task_queue = queue.Queue(task_num) result_queue = queue.Queue(task_num) def get_task(): return task_queue def get_result(): return result_queue # 建立類似的QueueManager class QueueManager(BaseManager): pass def run(): # Windows下繫結呼叫介面不能使用lambda,所以只能先定義函式再繫結 QueueManager.register('get_task_queue', callable = get_task) QueueManager.register('get_result_queue', callable=get_result) #繫結埠並設定驗證口令,windows下需要填寫ip地址,Linux中不填預設為本地 manager = QueueManager(address=('127.0.0.1', 8001), authkey='jap'.encode('utf-8')) # 啟動 manager.start() try: # 通過網路獲取任務佇列和結果佇列 task = manager.get_task_queue() result = manager.get_result_queue() # 新增任務 for url in ["JAP君url:"+str(i) for i in range(500)]: print("新增任務 %s" %url) task.put(url) print("正在獲取結果...") for i in range(500): print("result is %s" %result.get(timeout=10)) except: print('Manager error') finally: # 一定要關閉,否則會報管道未關閉的錯 manager.shutdown() if __name__ == '__main__': # windows下多程序可能會出現問題,新增這句話可以解決 freeze_support() run()
上面就是我們的服務程序,我把解析都寫在了裡面,大家可以仔細看一下,接下來我們來寫任務程序(taskWorker),建立任務程序也比較簡單,只有簡單的四步:
-
建立一個類似的QueueManager物件,使用QueueManager註冊用於獲取queue的方法名稱,任務程序只能通過名稱來在網路上獲取queue,所以這裡一定要注意服務端和任務端的名稱要相同。
-
連結伺服器,埠和指令一定要與服務端相同
-
從網路上獲取queue,並且將其本地化。
-
從task對列中獲取任務,並且把結果寫入result對列。
import time from multiprocessing.managers import BaseManager # 建立類似的QueueManager class QueueManager(BaseManager): pass # 第一步:使用QueueManager註冊用於獲取Queue的方法名稱 QueueManager.register('get_task_queue') QueueManager.register('get_result_queue') # 第二步:連結到伺服器 server_addr = '127.0.0.1' print('Connect to server %s' %server_addr) # 埠和驗證的口令一定要保證相同 m = QueueManager(address = (server_addr, 8001), authkey='jap'.encode('utf-8')) # 從網路連線: m.connect() # 第三步:獲取queue的物件 task = m.get_task_queue() result = m.get_result_queue() # 第四部:從task佇列中獲取任務,並把結果寫入result佇列 while(not task.empty()): url = task.get(True, timeout = 5) print("run task download %s" %url) time.sleep(1) # 將結果寫入result佇列 result.put("%s --->success" %url) print("exit")
詳細的步驟也寫在裡面了,當然這個任務佇列,我們是可以建立多個的,每個任務程序都會完成自己的事,而不會干擾其他的任務程序,這也就讓我們的url不會重複的去爬取,從而完美的實現了多個程序來爬取我們的任務。
以上就是一個非常簡單的分散式程序的爬蟲小案例,大家可以通過這種方式去實戰自己的一個小專案,在這裡還說一下,我們是可以將我們的任務分佈到多臺機器上的,這樣我們就實現了大規模的爬取。