Python異步爬蟲實(shí)現(xiàn)原理與知識(shí)總結(jié)
一、背景
默認(rèn)情況下,用get請(qǐng)求時(shí),會(huì)出現(xiàn)阻塞,需要很多時(shí)間來等待,對(duì)于有很多請(qǐng)求url時(shí),速度就很慢。因?yàn)樾枰粋€(gè)url請(qǐng)求的完成,才能讓下一個(gè)url繼續(xù)訪問。一種很自然的想法就是用異步機(jī)制來提高爬蟲速度。通過構(gòu)建線程池或者進(jìn)程池完成異步爬蟲,即使用多線程或者多進(jìn)程來處理多個(gè)請(qǐng)求(在別的進(jìn)程或者線程阻塞時(shí))。
import time
#串形
def getPage(url):
print("開始爬取網(wǎng)站",url)
time.sleep(2)#阻塞
print("爬取完成?。?!",url)
urls = ['url1','url2','url3','url4','url5']
beginTime = time.time()#開始計(jì)時(shí)
for url in urls:
getPage(url)
endTime= time.time()#結(jié)束計(jì)時(shí)
print("完成時(shí)間%d"%(endTime - beginTime))

下面通過模擬爬取網(wǎng)站來完成對(duì)多線程,多進(jìn)程,協(xié)程的理解。
二、多線程實(shí)現(xiàn)
import time
#使用線程池對(duì)象
from multiprocessing.dummy import Pool
def getPage(url):
print("開始爬取網(wǎng)站",url)
time.sleep(2)#阻塞
print("爬取完成!??!",url)
urls = ['url1','url2','url3','url4','url5']
beginTime = time.time()#開始計(jì)時(shí)
#準(zhǔn)備開啟5個(gè)線程,并示例化對(duì)象
pool = Pool(5)
pool.map(getPage, urls)#urls是可迭代對(duì)象,里面每個(gè)參數(shù)都會(huì)給getPage方法處理
endTime= time.time()#結(jié)束計(jì)時(shí)
print("完成時(shí)間%d"%(endTime - beginTime))

完成時(shí)間只需要2s!!!!!!!!
線程池使用原則:適合處理耗時(shí)并且阻塞的操作
三、協(xié)程實(shí)現(xiàn)
單線程+異步協(xié)程!?。。。。。。。?!強(qiáng)烈推薦,目前流行的方式。
相關(guān)概念:

#%%
import time
#使用協(xié)程
import asyncio
async def getPage(url): #定義了一個(gè)協(xié)程對(duì)象,python中函數(shù)也是對(duì)象
print("開始爬取網(wǎng)站",url)
time.sleep(2)#阻塞
print("爬取完成!?。?,url)
#async修飾的函數(shù)返回的對(duì)象
c = getPage(11)
#創(chuàng)建事件對(duì)象
loop_event = asyncio.get_event_loop()
#注冊(cè)并啟動(dòng)looP
loop_event.run_until_complete(c)
#task對(duì)象使用,封裝協(xié)程對(duì)象c
'''
loop_event = asyncio.get_event_loop()
task = loop_event.create_task(c)
loop_event.run_until_complete(task)
'''
#Future對(duì)象使用,封裝協(xié)程對(duì)象c 用法和task差不多
'''
loop_event = asyncio.get_event_loop()
task = asyncio.ensure_future(c)
loop_event.run_until_complete(task)
'''
#綁定回調(diào)使用
async def getPage2(url): #定義了一個(gè)協(xié)程對(duì)象,python中函數(shù)也是對(duì)象
print("開始爬取網(wǎng)站",url)
time.sleep(2)#阻塞
print("爬取完成!??!",url)
return url
#async修飾的函數(shù)返回的對(duì)象
c2 = getPage2(2)
def callback_func(task):
print(task.result()) #task.result()返回任務(wù)對(duì)象中封裝的協(xié)程對(duì)象對(duì)應(yīng)函數(shù)的返回值
#綁定回調(diào)
loop_event = asyncio.get_event_loop()
task = asyncio.ensure_future(c2)
task.add_done_callback(callback_func) #真正綁定,
loop_event.run_until_complete(task)
輸出:

四、多任務(wù)協(xié)程實(shí)現(xiàn)
import time
#使用多任務(wù)協(xié)程
import asyncio
urls = ['url1','url2','url3','url4','url5']
async def getPage(url): #定義了一個(gè)協(xié)程對(duì)象,python中函數(shù)也是對(duì)象
print("開始爬取網(wǎng)站",url)
#在異步協(xié)程中如果出現(xiàn)同步模塊相關(guān)的代碼,那么無法實(shí)現(xiàn)異步
#time.sleep(2)#阻塞
await asyncio.sleep(2)#遇到阻塞操作必須手動(dòng)掛起
print("爬取完成?。?!",url)
return url
beginTime = time.time()
#任務(wù)列表,有多個(gè)任務(wù)
tasks = []
for url in urls:
c = getPage(url)
task = asyncio.ensure_future(c)#創(chuàng)建任務(wù)對(duì)象
tasks.append(task)
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))#不能直接放task,需要封裝進(jìn)入asyncio,wait()方法中
endTime = time.time()
print("完成時(shí)間%d"%(endTime - beginTime))

此時(shí)不能用time.sleep(2),用了還是10秒
對(duì)于真正爬取過程中,如在getPage()方法中真正爬取數(shù)據(jù)時(shí),即requests.get(url) ,它是基于同步方式實(shí)現(xiàn)。應(yīng)該使用異步網(wǎng)絡(luò)請(qǐng)求模塊aiohttp
參考下面代碼:
async def getPage(url): #定義了一個(gè)協(xié)程對(duì)象,python中函數(shù)也是對(duì)象
print("開始爬取網(wǎng)站",url)
#在異步協(xié)程中如果出現(xiàn)同步模塊相關(guān)的代碼,那么無法實(shí)現(xiàn)異步
#requests.get(url)#阻塞
async with aiohttp.ClintSession() as session:
async with await session.get(url) as response: #手動(dòng)掛起
page_text = await response.text() #.text()返回字符串,read()返回二進(jìn)制數(shù)據(jù),注意不是content
print("爬取完成?。?!",url)
return page_text

到此這篇關(guān)于Python異步爬蟲實(shí)現(xiàn)原理與知識(shí)總結(jié)的文章就介紹到這了,更多相關(guān)Python異步爬蟲內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python實(shí)現(xiàn)識(shí)別圖片為文字的示例代碼
這篇文章主要為大家詳細(xì)介紹了Python如何不調(diào)用三方收費(fèi)接口,照樣實(shí)現(xiàn)識(shí)別圖片為文字的功能。文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-08-08
python調(diào)用MySql保姆級(jí)圖文教程(包會(huì)的)
MySQL是當(dāng)今市場(chǎng)上最受歡迎的數(shù)據(jù)庫系統(tǒng)之一,由于大多數(shù)應(yīng)用程序需要以某種形式與數(shù)據(jù)交互,因此像Python這樣的編程語言提供了用于存儲(chǔ)和訪問這些數(shù)據(jù)的工具,這篇文章主要給大家介紹了關(guān)于python調(diào)用MySql的相關(guān)資料,需要的朋友可以參考下2024-12-12
python辦公自動(dòng)化(Excel)的實(shí)例教程
使用Excel自動(dòng)化處理,將會(huì)用到Python第三方庫,所以我們需要提前通過來進(jìn)行安裝,下面這篇文章主要給大家介紹了關(guān)于python辦公自動(dòng)化(Excel)的相關(guān)資料,需要的朋友可以參考下2022-11-11
Tensorflow tf.nn.depthwise_conv2d如何實(shí)現(xiàn)深度卷積的
這篇文章主要介紹了Tensorflow tf.nn.depthwise_conv2d如何實(shí)現(xiàn)深度卷積的,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
Python?matplotlib中plt.plot()函數(shù)的顏色參數(shù)設(shè)置及可以直接運(yùn)行的程序代碼
在數(shù)據(jù)可視化中matplotlib.pyplot模塊的plot函數(shù)是一個(gè)非常重要且常用的工具,用于繪制2D圖形,這篇文章主要給大家介紹了關(guān)于Python?matplotlib中plt.plot()函數(shù)的顏色參數(shù)設(shè)置及可以直接運(yùn)行的程序代碼,需要的朋友可以參考下2024-03-03
k-means 聚類算法與Python實(shí)現(xiàn)代碼
這篇文章主要介紹了k-means 聚類算法與Python實(shí)現(xiàn)代碼,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06
Python入門教程(二十)Python的Lambda表達(dá)式
這篇文章主要介紹了Python入門教程(二十)Python的Lambda表達(dá)式,lambda表達(dá)式是一行的函數(shù)。它們?cè)谄渌Z言中也被稱為匿名函數(shù),lambda表達(dá)式非常有用,可以讓代碼簡單,簡潔,需要的朋友可以參考下2023-04-04

