1. 程式人生 > 實用技巧 >python爬蟲 | 帶你入門布式程序爬蟲

python爬蟲 | 帶你入門布式程序爬蟲

本文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯絡我們以作處理

以下文章來源於騰訊雲 作者:使用者2769421

( 想要學習Python?Python學習交流群:1039649593,滿足你的需求,資料都已經上傳群檔案流,可以自行下載!還有海量最新2020python學習資料。 )

1.預備知識

今天咱們來扯一扯分散式程序爬蟲,對爬蟲有所瞭解的都知道分散式爬蟲這個東東,今天我們來搞懂一下分散式這個概念,從字面上看就是分開來佈置,確實如此它是可以分開來運作的。

分散式程序就是將程序分佈到多臺機器上去,充分利用每一臺機器來完成我們的爬蟲任務。分散式程序需要用到multiprocessing模板,multiprocessing模板不但支援多程序,它的managers子模組還支援把多程序分佈到多臺機器上。

我們可以寫一個服務程序作為排程者,然後將我們的爬蟲任務分佈給其他的多個程序當中去,我們依靠網路通訊來管理這些程序。

2.模擬一個分散式程序爬蟲

我們來模擬進行一個分散式程序的爬蟲吧,就比如我們需要抓取某個圖片網站的所有圖片,如果用我們的分散式程序的思想,我們會建立一個程序負責抓取圖片的連結地址,然後將這些連結地址存放到Queue中,另外的程序負責從Queue中讀取連結進行圖片的下載或者進行其他操作(存在本地).

其實我們的Queue是暴露在網路中的,通過分散式就是將其進行了封裝,其實也就是所謂的本地佇列的網路化。

接下來,我們來分析一下如何去建立一個分散式的服務程序,總體可以分為六步:

  1. 首先我們需要建立一個佇列queue,這個主要用作程序之間的通訊。總體來說就是兩種程序,一種是服務程序,一種是任務程序。服務程序建立任務佇列task_queue,用作傳遞任務給任務程序的通道。服務程序又建立result_queue,作為任務程序完成任務後回覆服務程序的通道。在分散式程序的環境下,我們需要通過Queuemanager 獲得的Queue介面來新增任務。
  2. 把我們在第一步中佇列在網路上進行註冊,暴露給其他的程序或者主機,註冊後獲得網路佇列,相當於本地佇列的映像。
  3. 建立Queuemanager的物件,並且例項化,繫結埠和口令
  4. 啟動第三步中建立的例項,即啟動管理manager,監管資訊通道
  5. 通過管理例項的方法獲取到通過網路訪問的queue物件,也就是把網路物件實體化成本地的一個佇列。
  6. 建立任務到“本地”佇列中,自動上傳任務到網路佇列中,分配給任務程序進行處理。

我們就來寫一下服務程序的程式碼 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),建立任務程序也比較簡單,只有簡單的四步:

  1. 建立一個類似的QueueManager物件,使用QueueManager註冊用於獲取queue的方法名稱,任務程序只能通過名稱來在網路上獲取queue,所以這裡一定要注意服務端和任務端的名稱要相同。

  2. 連結伺服器,埠和指令一定要與服務端相同

  3. 從網路上獲取queue,並且將其本地化。

  4. 從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不會重複的去爬取,從而完美的實現了多個程序來爬取我們的任務。

以上就是一個非常簡單的分散式程序的爬蟲小案例,大家可以通過這種方式去實戰自己的一個小專案,在這裡還說一下,我們是可以將我們的任務分佈到多臺機器上的,這樣我們就實現了大規模的爬取。