最近在寫一個自動化腳本,從某電商網站批量獲取手機設備信息參數,基於python + requests完成腳本開發,但是實際運行效率上並不是特別滿意。無意中看到了HTTPX,在功能性和效率性上,給了我眼前一亮的感覺。
本文就來揭秘HTTPX的基本使用和高級特性用法。
HTTPX是Python3的全功能HTTP客戶端,它提供同步和異步API,並支持HTTP/1.1和HTTP/2。
根據官網的描述,總結有如下特點:
github介紹:https://github.com/encode/httpx
文檔介紹:https://www.python-httpx.org/
httpx的安裝很簡單,直接pip就完事了。
安裝命令如下:
pip install httpx
httpx還支持命令行方式,需要安裝httpx[cli]
pip install 'httpx[cli]'
使用例子:
httpx http://httpbin.org/json
get請求和post請求,直接導包然後get方法或者post方法就行了。使用方式和requests庫很類似。
需要的請求參數和requests庫的get請求參數差不多,也支持代理模式發送請求、重定向、證書認證等。
代碼如下:
r = httpx.get('http://www.baidu.com')
print(r.status_code)
post請求對於json、formdata、files類型支持也比較全面。
代碼如下:
r = httpx.post(url='http://api.bakend.com/saveResult',json={'name':'mike'})
print(r.json())
r = httpx.delete('http://www.baidu.com')
r = httpx.put('http://www.baidu.com')
r = httpx.head(''http://www.baidu.com')
r = httpx.options('http://www.baidu.com')
以上就是基本使用方式,這裡並沒有什麼特別之處,我們接著放下看。
如果使用來自requests,httpx.Client()可以使用它來代替requests.Session()。主要優勢是更有效地利用網絡資源,當發出API請求請求時,HTTPX會為為每個請求建立一個新連接(連接不被重)。隨著對主機的請求數量增加,這很快就會變得低效。
另一方面,Client實例使用HTTP連接池。這意味著當向同一主機發出多個請求時,Client將重用底層TCP連接,而不是為每個請求重新創建一個。
這可以帶來顯著的性能提升:
代碼如下:
Client是作為上下文管理器。with這將確保在離開塊時正確清理連接。
with httpx.Client() as client:
headers = {'os': 'Android'}
r = client.get('https://www.baidu.com', headers=headers)
或者,可以使用以下命令顯式關閉連接池而不使用阻塞.close():
client = httpx.Client()
try:
client.get('https://www.baidu,com')
finally:
client.close()
使用過requests庫的同學應該知道,它在處理批量請求、爬蟲等場景,需要循環等待每個請求發送完成腳本,在效率方面表現的一般。
HTTPX可以使用異步方式發送網絡請求,異步是一種比多線程更高效的並發模型,並且可以提供顯著的性能優勢並支持使用長壽命的網絡連接,例如WebSockets。
要發出異步請求,需要一個AsyncClient,使用await關鍵字修飾get方法。
async def get_result():
async with httpx.AsyncClient() as client:
resp = await client.get('http://httpbin.org/get')
assert resp.status_code == 200
html = resp.text
asyncio.run(get_result())
這裡主要使用HTTPX異步請求和request的請求,做一個請求耗時對比。
request的Session方式
def request_post_json():
print('----------- 同步請求 -----------')
url = host + "/responseTime/insert"
headers = {
'Content-Type': 'application/json',
}
payload = {}
payload['taskname'] = '響應測試'
payload['appnname'] = 999
payload['platform'] = platform.Android.value
payload['scenes'] = scenes.home.value
payload['videocount'] = 5 # 視頻個數
payload['grouptime'] = ','.join(["11.5", "11.6", "11.3"]) # 耗時數組
payload['avgtime'] = 5.55 # 平均耗時
payload['author'] = 'xinxi'
print(json.dumps(payload, indent=4))
r = requests.Session()
response = r.post(url, headers=headers, json=payload)
print(response.text)
for i in range(100):
request_post_json()
endTime = time.time()
print(endTime - startTime)
耗時:
15.002s
HTTPX異步請求
async def httpx_post_json():
print('----------- 異步請求 -----------')
url = host + "/responseTime/insert"
print(url)
headers = {
'Content-Type': 'application/json',
}
payload = {}
payload['taskname'] = '響應測試'
payload['appnname'] = 99
payload['platform'] = platform.Android.value
payload['scenes'] = scenes.home.value
payload['videocount'] = 5 # 視頻個數
payload['grouptime'] = ','.join(["11.5", "11.6", "11.3"]) # 耗時數組
payload['avgtime'] = 5.55 # 平均耗時
payload['author'] = 'xinxi'
async with httpx.AsyncClient() as client:
resp = await client.post(url, headers=headers, json=payload)
assert resp.status_code == 200
html = resp.text
print(html)
startTime = time.time()
loop = asyncio.get_event_loop()
task = [httpx_post_json() for i in range(100)] # 把任務放入數組,准備給事件循環器調用
loop.run_until_complete(asyncio.wait(task))
loop.close()
endTime = time.time()
print(endTime - startTime)
耗時:
3.070s
可以看出HTTPX異步請求方式明顯比request的請求耗時降低了很多。
以上就是HTTPX的一些使用分享,在實際工作中能替代requests完成工作。另外,加持高級用法,更可以極大提高工作效率。