Pythonhttpx教程展示了如何使用httpx模块在Python中创建HTTP请求。httpx允许创建同步和异步HTTP请求。
httpx模块
HTTPX是Python3的HTTP客户端,它提供同步和异步API,并支持HTTP/1.1和HTTP/2。它具有与流行的Python请求库类似的API。HTTPX需要Python3.6+。
$ pip install httpx
我们使用pip命令安装模块。
httpx支持异步网络请求。通过结合使用httpx和asyncio模块以及async和await关键字,我们可以生成异步Web请求。这可能会大大提高我们程序的效率。
HTTP
超文本传输协议(HTTP)是分布式协作超媒体信息系统的应用协议。HTTP是万维网数据通信的基础。
Pythonhttpx状态码
在第一个示例中,我们确定网页的状态。状态代码由status_code属性确定。
#!/usr/bin/python
import httpx
r = httpx.head('http://webcode.me')
print(r.status_code)
该示例创建对webcode.me网站的同步HEAD请求并检索http响应。从响应中,我们得到状态码。
$ ./sync_status.py 200
PythonhttpxGET请求
以下示例创建同步GET请求。
#!/usr/bin/python
import httpx
r = httpx.get('http://webcode.me')
print(r.text)
我们使用httpx.get方法生成对网页的GET请求。检索页面并将其HTML代码打印到控制台。
$ ./sync_get.py
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My html page</title>
</head>
<body>
<p>
Today is a beautiful day. We go swimming and fishing.
</p>
<p>
Hello there. How are you?
</p>
</body>
</html>
有一个params选项可以随请求发送查询参数。
#!/usr/bin/python
import httpx
payload = {'name': 'John Doe', 'occupation': 'gardener'}
r = httpx.get('https://httpbin.org/get', params = payload)
print(r.text)
该示例使用GET请求发送查询参数。
$ ./sync_query_params.py
{
"args": {
"name": "John Doe",
"occupation": "gardener"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br",
"Host": "httpbin.org",
"User-Agent": "python-httpx/0.16.1",
"X-Amzn-Trace-Id": "Root=1-600817ec-25cb3dea461b3e7a6f21df27"
},
...
"url": "https://httpbin.org/get?name=John+Doe&occupation=gardener"
}
PythonhttpxPOST表单请求
POST请求是用httpx.post方法生成的。
使用application/x-www-form-urlencoded,数据在请求正文中发送;键和值被编码在由“&”分隔的键值元组中,键和值之间有一个“=”。
#!/usr/bin/python
import httpx
payload = {'name': 'John Doe', 'occupation': 'gardener'}
r = httpx.post('https://httpbin.org/post', data=payload)
print(r.text)
我们生成一个带有FORM数据的同步POST请求到httpbin.org/post。有效负载设置为data选项。
$ ./sync_post_form.py
{
"args": {},
"data": "",
"files": {},
"form": {
"name": "John Doe",
"occupation": "gardener"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br",
"Content-Length": "33",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "python-httpx/0.16.1",
"X-Amzn-Trace-Id": "Root=1-600819fd-5e7b28a97b2484c8438a6f2e"
},
"json": null,
...
"url": "https://httpbin.org/post"
}
Pythonhttpx流数据
对于较大的下载,我们可以流式传输不会立即将整个响应主体加载到内存中的响应。对于流式传输,我们使用httpx.stream方法。
#!/usr/bin/python
import httpx
url = 'https://download.freebsd.org/ftp/releases/amd64/amd64/ISO-IMAGES/12.0/FreeBSD-12.0-RELEASE-amd64-mini-memstick.img'
with open('FreeBSD-12.0-RELEASE-amd64-mini-memstick.img', 'wb') as f:
with httpx.stream('GET', url) as r:
for chunk in r.iter_bytes():
f.write(chunk)
该示例下载FreeBSD操作系统的映像。我们使用iter_bytes方法遍历二进制内容。
Pythonhttpx异步GET请求
以下示例生成一个简单的异步GET请求。
#!/usr/bin/python
import httpx
import asyncio
async def main():
async with httpx.AsyncClient() as client:
r = await client.get('http://test.webcode.me')
print(r.text)
asyncio.run(main())
在示例中,我们异步检索一个小的HTML页面。
import httpx import asyncio
我们需要导入httpx和asyncio模块。asyncio模块是一个使用async/await语法编写并发代码的库;它通常非常适合IO密集型任务。
async def main():
使用asyncdef,我们创建了一个协程。协程用于协作式多任务处理。
async with httpx.AsyncClient() as client:
我们创建一个异步HTTP客户端。该库还必须支持异步编程模型。
r = await client.get('http://test.webcode.me')
使用await关键字,启动get协程,然后程序恢复执行;协程将执行的控制权交还给事件循环。所以程序不会停止等待请求。当请求到达时,事件循环在等待协程的地方继续。
asyncio.run(main())
run方法启动事件循环并调用main协程。事件循环是注册、执行和取消异步函数的中心点。
Pythonhttpx多个异步GET请求
asyncio.gather函数并发运行协程。
#!/usr/bin/python
import httpx
import asyncio
async def get_async(url):
async with httpx.AsyncClient() as client:
return await client.get(url)
urls = ["http://webcode.me", "https://httpbin.org/get"]
async def launch():
resps = await asyncio.gather(*map(get_async, urls))
data = [resp.text for resp in resps]
for html in data:
print(html)
asyncio.run(launch())
该示例生成两个异步GET请求。
async def get_async(url):
async with httpx.AsyncClient() as client:
return await client.get(url)
这是生成异步GET请求的协程。
urls = ["http://webcode.me", "https://httpbin.org/get"]
我们有两个URL。
async def launch():
resps = await asyncio.gather(*map(get_async, urls))
data = [resp.text for resp in resps]
for html in data:
print(html)
通过内置的map函数,我们将get_async函数应用于URL列表。使用*(星号)运算符将返回的列表解压缩为位置参数。如果所有协程都成功完成,则结果是返回值(HTML代码)的聚合列表。
Pythonhttpx异步POST表单请求
以下示例显示了如何发送带有表单数据的异步POST请求。
#!/usr/bin/python
import httpx
import asyncio
async def main():
data = {'name': 'John Doe', 'occupation': 'gardener'}
async with httpx.AsyncClient() as client:
r = await client.post('https://httpbin.org/post', data=data)
print(r.text)
asyncio.run(main())
数据被传递给post协程的data选项。
Pythonhttpx异步POSTJSON请求
以下示例展示了如何使用JSON数据发送异步POST请求。
#!/usr/bin/python
import httpx
import asyncio
async def main():
data = {'int': 123, 'boolean': True, 'list': ['a', 'b', 'c']}
async with httpx.AsyncClient() as client:
r = await client.post('https://httpbin.org/post', json=data)
print(r.text)
asyncio.run(main())
数据设置为post协程的json选项。
Pythonhttpx异步流请求
该示例展示了如何在异步流中下载大型二进制文件。
#!/usr/bin/python
import httpx
import asyncio
url = 'https://download.freebsd.org/ftp/releases/amd64/amd64/ISO-IMAGES/12.0/FreeBSD-12.0-RELEASE-amd64-mini-memstick.img'
async def main():
with open('FreeBSD-12.0-RELEASE-amd64-mini-memstick.img', 'wb') as f:
async with httpx.AsyncClient() as client:
async with client.stream('GET', url) as r:
async for chunk in r.aiter_bytes():
f.write(chunk)
asyncio.run(main())
我们使用client.stream和aiter_bytes函数。
比较同步和异步请求
在下面两个例子中,我们比较了一组同步和异步请求的效率。使用time模块,我们计算经过的时间。
#!/usr/bin/python
import httpx
import time
urls = ['http://webcode.me', 'https://httpbin.org/get',
'https://google.com', 'https://stackoverflow.com',
'https://github.com', 'https://mozilla.org']
start_time = time.monotonic()
for url in urls:
r = httpx.get(url)
print(r.status_code)
print(f'Elapsed: {time.monotonic() - start_time}')
我们生成六个同步GET请求并计算经过的时间。
#!/usr/bin/python
import httpx
import asyncio
import time
async def get_async(url):
async with httpx.AsyncClient() as client:
return await client.get(url)
urls = ['http://webcode.me', 'https://httpbin.org/get',
'https://google.com', 'https://stackoverflow.com',
'https://github.com']
async def launch():
resps = await asyncio.gather(*map(get_async, urls))
data = [resp.status_code for resp in resps]
for status_code in data:
print(status_code)
start_time = time.monotonic()
asyncio.run(launch())
print(f'Elapsed: {time.monotonic() - start_time}')
我们生成六个异步GET请求。
$ ./multiple_async.py 200 200 200 200 200 Elapsed: 0.935432159982156 $ ./multiple_sync.py 200 200 200 200 200 200 Elapsed: 3.5428215700085275
在我们的案例中,差异超过2.5秒。
在本教程中,我们使用httpx模块在Python中生成了同步和异步Web请求。
列出所有Python教程。
