天天看點

多線程爬蟲

多線程爬蟲

多線程爬蟲

    建立爬蟲是為了提高效率,而建立多線程正是提高效率的方法之一,單線程爬蟲隻有一個線程,在每次通路網頁時,不能夠充分利用網絡帶寬,進而造成資源的浪費。

    Python在設計的時候,有一個全局解釋器(Global Interpreter Lock),導緻Python的多線程都是僞線程,其本質還是一個單線程,隻是這個線程每個事情隻做幾毫秒幾毫秒以後就儲存資料,換做其他的事,幾毫秒之後再做其他的事,一輪之後又回到第一件事,恢複資料再做幾秒,然後有重複剛才的動作。簡單來說就是同時在做幾件事。

多程序庫:

    multiprocessing本身是Python的多程序庫,用來處理與多程序相關的操作。由于程序與程序之間不能共享記憶體和堆棧空資源,而且啟動新的程序開銷也比其他線程大得多,是以使用多線程來爬取比使用多程序有更多的優勢。multiprocessing下面有一個dummy子產品,他可以是Python的線程使用multiprocessing的各種方法。

    dummy下面有一個Pool類,他用來實作多線程。這個線程池有一個Map()方法,可以讓線程池裡面的線程“同時”執行一個函數。

for i in range(10):
    print(i**i)
           

這種方式的運作效率或者說執行效率不高,而如果使用多線程技術,可以同時計算很多個數的平方。這時就需要使用multiprocessing來實作

from multiprocessing.dummy import Pool

    def Test(num):
        return num * num
    
    pool = Pool(3)
    oright1 = [x for x in range(10)]
    oright = pool.map(Test,oright1)
    print(f"計算0-9的平方和分别為: { oright }")
           

先初始化一個有3個線程的線程池,,這三個線程池負責計算10個數字的平方,注意是同時進行計算的。map方法接收了兩個參數(Test,oright1),第一個是函數名(注意不能帶括号),第二個參數是一個可疊代的對象,這個可疊代對象裡面的每一個元素都會被函數Test調用接收來作為參數,因為沒有使用IQ流操作,是以在Python GIL的影響下,使用三個線程并不會是代碼的運作時間小于單線程的運作時間(運作時等了好一會才出來,我以為是空指針異常呢,尴尬)。

除了清單以外,元祖、集合、字典都可以作為map()的第二個參數。

執行個體:

import requests
import time
from multiprocessing.dummy import  Pool

def query(url):
    requests.get(url)
    return url

start = time.time()
for i in range(100):
    query("http://baidu.com")
end = time.time()
print(f"單線程循環通路百度100次:耗時{ end - start}")

start = time.time()
url_list = []
for i in range (100):
    url_list.append("http://baidu.com")
pool = Pool(5)
pool.map(query,url_list)
end = time.time()
print(f"5次線程通路百度首頁:耗時:{ end - start}")
           

兩者進行對比就可以看出來兩者的差別。

單線程循環通路百度100次:耗時20.2206449508667
5次線程通路百度首頁:耗時:3.9783244132995605