本文原創釋出於微信公眾號「極客猴」,歡迎關注第一時間獲取更多原創分享
對於爬蟲程式,我們往往會很關注其爬蟲效率。影響爬蟲效率有幾個因素有,是否使用多執行緒,I/O 操作,是否同步執行等。其中 I/O 操作、同步執行是最影響爬蟲效率的。
眾所周知,Requests 庫一個優秀的 HTTP 庫,通過它可以非常簡單地發起 HTTP 請求。不過,這個庫所執行的網路請求都是同步。當爬蟲程式程式獲得 CPU 的時間片時,如果程式在進行 I/O 操作(例下載圖片),在這段 IO 執行的時間裡,CPU 處於空閒中,這樣會造成 CPU 的計算能力就被浪費了。
如果 CPU 能將等待時間利用起來,那麼爬蟲效率就提高了。那就需要對程式進行改造,將 I/O 同步操作變成非同步操作。本文內容是介紹一個強大的非同步 I/O 操作的庫 —— aiohttp。
1 aiohttp 介紹
說到 aiohttp ,不得不說下 asyncio 。asyncio 是 Python 3.4 版本引入的標準庫。它工作模式是單執行緒併發,使用協同執行 I/O 操作。asyncio 的程式設計模型就是一個訊息迴圈。我們從 asyncio 模組中直接獲取一個 EventLoop 的引用,然後把需要執行的協程扔到 EventLoop 中執行,就實現了非同步 IO。
使用 asyncio 實現一個非同步函式 hello() 的例子:
import asyncio
@asyncio.coroutine # 修飾符,等同於 asyncio.coroutine(hello())
def hello():
print("Hello world!")
# 非同步呼叫asyncio.sleep(1):
r = yield from asyncio.sleep(1)
print("Hello again!")
# 獲取EventLoop:
loop = asyncio.get_event_loop()
# 執行coroutine
loop.run_until_complete(hello())
loop.close()
複製程式碼
而 aiohttp 則是基於 asyncio 實現的 HTTP 框架。 aiohttp 全稱是 Async http client/server framework。翻譯成中文是非同步 HTTP 的客戶端/伺服器框架。從名字中,我們可知 aiohttp 是分為伺服器端和客戶端,專門非同步處理 HTTP 的請求。
2 aiohttp 安裝
安裝 aiohttp 可以通過 pip 方式安裝,在終端中執行安裝命令即可。
pip install aiohttp
複製程式碼
3 async/await 語法
前面我們講到非同步 I/O 的用法,但是宣告非同步函式比較繁瑣,還需要依賴 yield 語法。在 Python 3.5 中,引入了 async/await 關鍵字,使得非同步回撥的寫法更加直觀和人性化。
在函式 def 之前增加關鍵字async,表示這個函式是非同步函式。相當於替代語法@asyncio.coroutine
。具體例子例如:
async def hello():
print("Hello World!")
複製程式碼
另外使用 await 替換了 yield from
, 表示這部分操作為非同步操作。
async def hello():
print("Hello World!")
r = await asyncio.sleep(1)
print("Hello again!")
複製程式碼
最後執行非同步函式,還是需要用到 EventLoop 引用,然後利用協程執行非同步函式。最終的程式碼如下:
import asyncio
async def hello():
print("Hello world!")
r = await asyncio.sleep(1)
print("Hello again!")
if __name__ == '__main__':
loop = asyncio.get_event_loop()
tasks = [hello(), ]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
複製程式碼
執行結果如下:
Hello world!
>> 會暫停一秒鐘
Hello again!
複製程式碼
4 aiohttp 基本用法
我們使用 aiohttp 以 GET 方式向httpbin.org
網站發起一個 HTTP 請求。因為是 aiohttp 是非同步處理 HTTP 請求。所以還必須遵循 Python 的非同步函式語法,即需使用 async/await 語法。
使用 aiohttp 發起一個 HTTP 請求,具體編寫可以分為以下幾步: 1)使用 async 定義非同步函式 2)通過 aiohttp.ClientSession 獲取一個 session 物件 3)用該 session 物件以 GET、POST、PUT 等方式去請求網頁 4)最後獲取 EventLoop 引用,執行非同步函式。
import asyncio
import aiohttp
# 定義非同步函式 main()
async def main():
# 獲取 session 物件
async with aiohttp.ClientSession() as session:
# get 方式請求 httbin async with session.get('http://httpbin.org/get') as response:
print(response.status)
print(await response.text())
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
複製程式碼
aiohttp 支援自定義 headers、設定超時時間、設定代理、自定義 cookie 等。
import asyncio
import aiohttp
url = 'http://httpbin.org/post'
headers = {
'User-agent': "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
}
data = {
'data': 'person data',
}
# 定義非同步函式 main()
async def main():
# 獲取 session 物件
async with aiohttp.ClientSession() as session:
# post 方式請求 httbin
async with session.post(url=url, headers=headers, data=data) as response:
print(response.status)
print(await response.text())
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
複製程式碼
關於 aiohttp 更多用法,可以執行閱讀官網文件。說句實話,aiohttp 跟 Requests 的用法大同小異。如果你已經學會了 Requests 庫,很快就能掌握 aiohttp 的用法。
本文首發於微信公眾號,原文地址是 想提高爬蟲效率?aiohttp 瞭解下。隨時歡迎轉載文章, 轉載請聯絡號主開通白名單,尊重作者的原創。本人微信公眾號「極客猴」,每週分享 Python 原創乾貨。涉及網路爬蟲、資料分析、web 開發等方向。