最近在写一个自动化脚本,从某电商网站批量获取手机设备信息参数,基于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完成工作。另外,加持高级用法,更可以极大提高工作效率。