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教程。