天天看點

多協程爬蟲

協程是一種使用者态的輕量級線程,使用協程有衆多好處:

第一個好處是協程像一種在程式級别模拟系統級别的程序,由于是單線程,并且少了上下文切換,是以相對來說系統消耗很少,而且網上的各種測試也表明協程确實擁有驚人的速度。

第二個好處是協程友善切換控制流,這就簡化了程式設計模型。協程能保留上一次調用時的狀态(所有局部狀态的一個特定組合),每次過程重入時,就相當于進入了上一次調用的狀态。

第三個好處是協程的高擴充性和高并發性,一個CPU支援上萬協程都不是問題,是以很适合用于高并發處理。

協程也有缺點。

第一,協程的本質是一個單線程,不能同時使用單個CPU的多核,需要和程序配合才能運作在多CPU

上。

第二,有長時間阻塞的操作時不要用協程,因為可能會阻塞整個程式。

在 Pythongevent的協程中可以使用庫。 gevent也可以使用pip安裝:

pip install gevent

安裝完 gevent,就可以使用 gevent進行爬蟲了,代碼如下:

import gevent
from gevent.queue import Queue, Empty
import time
import requests
from gevent import monkey

link_list = []
# 把下面有可能有I0操作的單獨做上标記
monkey.patch_all()  # 将IO轉為異步執行的函數
with open('alexa.txt', 'r') as file:
    file_list = file.readlines()
    for each in file_list:
        link = each.replace('\n', '')
        link_list.append(link)


def crawler(index):
    process_id = 'Process--' + str(index)
    while not workQueue.empty():
        url = workQueue.get(timeout=2)
        try:
            r = requests.get(url, timeout=20)
            print(process_id, workQueue.qsize(), r.status_code, url)
        except Exception as e:
            print(process_id, workQueue.qsize(), url, 'Error:', e)


def boss():
    for url in link_list:
        workQueue.put_nowait(url)


if __name__ == '__main__':

    workQueue = Queue(1010)
    gevent.spawn(boss).join()
    start = time.time()
    jobs = []
    for i in range(10):
        jobs.append(gevent.spawn(crawler, i))
    gevent.joinall(jobs)
    end = time.time()
    print('gevent' + 'Queue多協程爬蟲的總時間為:', end - start)
    print('Main Ended!')
           

在上述代碼中,我們首先使用了

from gevent import monkey

monkey. patch_all()

這樣可以實作爬蟲的并發能力,如果沒有這兩句,整個抓取過程就會變成依次抓取。 geventmonkey庫中的能把可能有l0操作的單獨做上标記,将1O變成可以異步執行的函數。我們還是用 Queue建立隊列,但是在

gevent中需要使用:gevent. spawn(boss).join()将隊列中加入的内容整合到 gevent中。接下來使用如下代碼建立多協程的爬蟲程式:

for i in range(10):
        jobs.append(gevent.spawn(crawler, i))
    gevent.joinall(jobs)
           

運作上述代碼,可以發現開了10個協程,爬蟲的速度變得非常快,多協程爬蟲能夠很好地支援高并發的

工作。