多任務非同步協程asyncio asyncio的使用 多任務協程 aiohttp的使用 非同步協程爬蟲案例 基於aiohttp的多任務協程的爬蟲 ...
多任務非同步協程asyncio
特殊函數:
- 就是async關鍵字修飾的一個函數的定義
- 特殊之處:
- 特殊函數被調用後會返回一個協程對象
- 特殊函數調用後內部的程式語句沒有被立即執行
- 協程
- 對象。協程==特殊的函數。協程表示的就是一組特定的操作。
- 任務對象
- 高級的協程(對協程的進一步的封裝)
- 任務對象==協程==特殊的函數
- 任務對象==特殊的函數
- 綁定回調:
- task.add_done_callback(task)
- 參數task:當前回調函數對應的任務對象
- task.result():返回的就是任務對象對應的特殊函數的返回值
- 事件迴圈對象
- 創建事件迴圈對象
- 將任務對象註冊到該對象中並且開啟該對象
- 作用:loop可以將其內部註冊的所有的任務對象進行非同步執行
- 掛起:就是交出cpu的使用權。
await:被用做在特殊函數的內部,在被阻塞的時候
wait:給每一個任務賦予一個可被掛起的許可權
#【重點】在特殊函數內部的實現中,不可以出現不支持非同步的模塊(例如time,requests)代碼,如果出現了,則會中斷整個的非同步效果!!!
asyncio的使用
import asyncio
import time
from time import sleep
# 特殊函數
async def get_request(url):
print('正在下載: ',url)
sleep(2)
print('下載完畢: ',url)
return 'page_text'
# 回調函數,普通函數
def parse(task):
# 參數表示任務對象
print('i am callback',task.result())
start = time.time()
# 調用特殊函數
func = get_request('www.xx.com')
# 創建任務對象
task = asyncio.ensure_future(func)
# 給任務對象綁定回調函數
task.add_done_callback(parse)
# 創建一個事件迴圈對象
loop = asyncio.get_event_loop()
# 讓loop執行一個任務
loop.run_until_complete(task)
print("總耗時:",time.time()-start) #總耗時: 2.0017831325531006
多任務協程
import asyncio
import time
# 特殊函數
async def get_request(url):
print('正在下載',url)
# time.sleep(2) 不支持非同步的模塊 會中斷整個的非同步效果
await asyncio.sleep(2)
print('下載完成',url)
return 'page_text'
def parse(task):
print(task.result())
start = time.time()
urls = ['www.xxx1.com','www.xxx2.com','www.xxx3.com']
tasks = [] #存放多任務
for url in urls:
# 調用特殊函數
func = get_request(url)
# 創建任務對象
task = asyncio.ensure_future(func)
# 給任務對象綁定回調函數
task.add_done_callback(parse)
tasks.append(task)
# 創建事件迴圈對象
loop = asyncio.get_event_loop()
# 執行任務
loop.run_until_complete(asyncio.wait(tasks))
print('總耗時:',time.time()-start) #2.0015313625335693
aiohttp的使用
- requests一定是不支持非同步
- aiohttp是一個支持非同步的網路請求模塊
- 環境安裝
- 編碼流程:
- 大致的架構:
with aiohttp.ClientSession() as s:
#s.get(url,headers,params,proxy="http://ip:port")
with s.get(url) as response:
#response.read()二進位(.content)
page_text = response.text()
return page_text
- 補充細節
- 在每一個with前加上async
- 需要在每一個阻塞操作前加上await
async with aiohttp.ClientSession() as s:
#s.get(url,headers,params,proxy="http://ip:port")
async with await s.get(url) as response:
#response.read()二進位(.content)
page_text = await response.text()
return page_text
非同步協程爬蟲案例
# 需求用多任務非同步協程獲取百度,搜狗,京東,淘寶的頁面源碼數據,並簡單解析
import asyncio
import requests
import time
from lxml import etree
urls = ['https://www.baidu.com','http://www.taobao.com/','http://www.jd.com/','https://www.sogou.com/']
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
}
# 特殊函數
async def get_request(url):
print('正在下載',url)
page_text = requests.get(url,headers=headers).text
print(url,'下載完成')
return page_text
# 回調函數
def parse(task):
page_text = task.result()
tree = etree.HTML(page_text)
div = tree.xpath('//div')
print(div)
start = time.time()
tasks = []#存放多任務
for url in urls:
func = get_request(url)
task = asyncio.ensure_future(func)
task.add_done_callback(parse)
tasks.append(task)
# 創建事件要在迴圈外
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
print('總耗時:',time.time()-start)
#根據結果發現執行並不是非同步,原因是requests不是非同步模塊,所以整個程式不會非同步執行
基於aiohttp的多任務協程的爬蟲
# 需求用多任務非同步協程獲取百度,搜狗,京東,淘寶的頁面源碼數據,並簡答解析
import asyncio
import requests
import time
import aiohttp
from lxml import etree
urls = ['https://www.baidu.com','http://www.taobao.com/','http://www.jd.com/','https://www.sogou.com/']
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
}
# 特殊函數
async def get_request(url):
async with aiohttp.ClientSession() as s:
# s.get(url,headers,params,proxy="http://ip:port")
async with await s.get(url,headers=headers) as response:
print('正在下載', url)
# response.read()二進位(.content)
page_text = await response.text()
print(url, '下載完成')
return page_text
# 回調函數
def parse(task):
page_text = task.result()
tree = etree.HTML(page_text)
div = tree.xpath('//div')
print(div)
start = time.time()
tasks = []#存放多任務
for url in urls:
func = get_request(url)
task = asyncio.ensure_future(func)
task.add_done_callback(parse)
tasks.append(task)
# 創建事件要在迴圈外
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
print('總耗時:',time.time()-start) #總耗時: 3.0848371982574463