非同步網路模組之aiohttp的使用

公號_python學習開發發表於2018-10-25


平時我們也許用的更多的是requests模組,或者是requests_hml模組,但是他們都屬於阻塞型別的不支援非同步,速度很難提高,於是後來出現了非同步的grequests,開始了非同步網路請求,速度得到了大大的提升,但是今天我們要說的另外的一個比較非同步網路請求模組-aiohttp。

什麼是aiohhtp?

要學習一個模組,首先要知道這個模組都能做什麼,我們從官網上找到了關於aiohttp的解釋。

Asynchronous HTTP Client/Server for asyncio and Python.
Supports both Client and HTTP Server.
Supports both Server WebSockets and Client WebSockets out-of-the-box without the Callback Hell.
Web-server has Middlewares, Signals and pluggable routing.

大概意思是說aiohttp是一個非同步http網路模組分為了客戶端和服務端,同時支援websocket的使用,另外不用擔心在使用過程中多次回撥導致回撥地獄情況出現。

如何安裝?

在linux直接pip安裝應該沒什麼問題,一般都坑在windows系統上,我使用win10 64位系統直接安裝也是沒有出現什麼問題,
官網上推薦的是先按照cchardet,這是一個關於網頁編碼的模組直接執行下面命令即可

pip install cchardet複製程式碼

之後我們安裝

pip install aiohttp複製程式碼

後面的操作我們需要還要安裝一個協程模組asyncio。

pip install asyncio複製程式碼

ok,沒什麼問題安裝我們就到這裡了。

如何使用

我們先看一段程式碼,後面會對程式碼作出解釋。

import asyncio #匯入協程包import aiohttp #匯入aiohttp from lxml import html   #匯入html解析模組headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36"}async def getsource(url):       conn=aiohttp.TCPConnector(verify_ssl=False)#防止ssl報錯       async with aiohttp.ClientSession(connector=conn) as session: #建立session             async with session.get(url,headers=headers,timeout=60) as req: #獲得請求                 if req.status==200: #判斷請求碼                    source=await req.text()#使用await關鍵字獲取返回結果                    print(html.fromstring(source).xpath("//title/text()")[0]) #獲取網頁標題                 else:                     print("訪問失敗")if __name__=="__main__":         full_urllist= ["https://www.baidu.com","https://www.cnblogs.com","https://www.jianshu.com"]         event_loop = asyncio.get_event_loop() #建立事件迴圈         tasks = [getsource(url) for url in full_urllist]         results = event_loop.run_until_complete(asyncio.wait(tasks))#等待任務結束複製程式碼

-----------------------------------------執行結果---------------------------------------------


部分內容已經在上面的程式碼中標註了,下面我們開始對上面的內容進行分析。

async/await

首先我們需要知道關鍵字async/await,在方法的面前加關鍵字async之後該方法就成了一個協程了,
一般await關鍵字使用的使用所在的方法必須帶有async,關於兩個關鍵字的演變,要從yield說起,
演變過程請參考http://python.jobbole.com/86069/,這裡只要知道是協程意思就行了。
首先我定義了聯結器並取消ssl安全驗證,我們使用verify_ssl使其等於False,預設是True的。

TCPConnector

因為有的網站請求的時候會驗證ssl證照,如果是自簽名的ssl證照會出錯。

conn=aiohttp.TCPConnector(verify_ssl=False)#防止ssl報錯複製程式碼

下面是關於TCPConnector的所有引數部分。

class aiohttp.TCPConnector(*, ssl=None, verify_ssl=True, fingerprint=None, use_dns_cache=True, ttl_dns_cache=10, family=0, ssl_context=None, local_addr=None, resolver=None, keepalive_timeout=sentinel, force_close=False, limit=100, limit_per_host=0, enable_cleanup_closed=False, loop=None)

limit

為了限制同時開啟的連線數量,我們可以將限制引數傳遞給聯結器:

conn = aiohttp.TCPConnector(limit=30)#同時最大進行連線的連線數為30,預設是100,limit=0的時候是無限制複製程式碼

limit_per_host:

conn = aiohttp.TCPConnector(limit_per_host=30)#預設是0複製程式碼

同一端點的最大連線數量。同一端點即(host, port, is_ssl)完全相同.

ClientSession

首先我們建立一個session物件,向下面這樣使用async宣告非同步,同時with上下文關鍵字 省去了關閉連線的程式碼,

async with aiohttp.ClientSession(connector=conn) as session: 複製程式碼

下面是ClientSession的所有引數,這裡用的比較多的是connector,headers,cookies其他的引數大家可以去自己探索一下。

class aiohttp.ClientSession(*, connector=None, loop=None, cookies=None, headers=None, skip_auto_headers=None, auth=None, json_serialize=json.dumps, version=aiohttp.HttpVersion11, cookie_jar=None, read_timeout=None, conn_timeout=None, timeout=sentinel, raise_for_status=False, connector_owner=True, auto_decompress=True, proxies=None

session.get

上面我們建立了session物件,然後我們就要進行請求具體的網站了。

async with session.get(url,headers=headers,timeout=60) as req: #獲得請求複製程式碼

這一步我們像使用requests那樣傳入headers引數並指定最大超時為60s。

ClientResponse

然後我們判斷請求是否情況,之後我們使用await req.text()獲取了網頁的原始碼,注意這裡必須使用await關鍵字來獲取協程的結果。然後我們使用了lxml模組獲取這三個網頁的title標題。

到目前為止我們只是定義了一個協程,並沒有真正的執行它接下來我們看看main方法是做什麼的。

         full_urllist= ["https://www.baidu.com","https://www.cnblogs.com","https://www.jianshu.com"]         event_loop = asyncio.get_event_loop() #建立時間迴圈         tasks = [getsource(url) for url in full_urllist]         results = event_loop.run_until_complete(asyncio.wait(tasks))#等待任務結束複製程式碼

首先我定義了一個列表含有三個目標url,當前你可以定義更多。
asyncio.get_event_loop方法可以建立一個事件迴圈,然後使用run_until_complete將協程註冊到事件迴圈,並啟動事件迴圈。
協程物件不能直接執行,在註冊事件迴圈的時候,其實是run_until_complete方法將協程包裝成為了一個任務(task)物件。所謂task物件是Future類的子類。儲存了協程執行後的狀態,用於未來獲取協程的結果。

asyncio.ensure_future(coroutine) 和 loop.create_task(coroutine)都可以建立一個task,run_until_complete的引數是一個futrue物件。當傳入一個協程,其內部會自動封裝成task,task是Future的子類。isinstance(task, asyncio.Future)將會輸出True。

簡單的我們就瞭解到這吧,如果有什麼不懂的地方請留言大家一起討論。


更多文章關注公眾號:python學習開發

部落格園地址:www.cnblogs.com/c-x-a


相關文章