Python3 新一代Http请求库Httpx使用(详情版)(上)

简介: Python3 新一代Http请求库Httpx使用(详情版)

我们经常使用Python语言的朋友们都清楚,requests 是使用率非常高的 HTTP 库,甚至更早Python2中使用的是 urllib、urllib2 ,也给我们提供了许多方便的功能。


但是自从 Python 3.6 之后的内置 asyncio 模块的兴起,异步方式 更加符合大众或业务上的需求。所以新一代 HTTP库 Httpx 应运而生。


它可以同时使用异步和同步方式来发送 HTTP 请求,并且比 requests 更快。它也支持许多 HTTP/2 特性,比如多路复用和服务端推送。


一、 概述


1、 简介


Httpx 是 Python 3 的全功能 HTTP 客户端,它提供同步和异步 API,并支持 HTTP/1.1 和 HTTP/2。


官方API:https://www.python-httpx.org/


该库的特性:


HTTPX 建立在公认的可用性之上requests,并为您提供:

  • 广泛兼容请求的 API
  • 标准同步接口,但如果需要,可以支持异步
  • HTTP/1.1和 HTTP/2 支持
  • 能够直接向WSGI 应用程序ASGI 应用程序发出请求。
  • 到处都是严格的超时。
  • 完全类型注释。
  • 100% 的测试覆盖率。


加上requests...的所有标准功能

  • 国际域名和 URL
  • 保持活动和连接池
  • 具有 Cookie 持久性的会话
  • 浏览器式 SSL 验证
  • 基本/摘要认证
  • 优雅的键/值 Cookie
  • 自动减压
  • 自动内容解码
  • Unicode 响应体
  • 多部分文件上传
  • HTTP(S) 代理支持
  • 连接超时
  • 流式下载
  • .netrc 支持
  • 分块请求


安装方式:

pip install httpx  # 安装库
pip install httpx[http2]  # 获取http2的支持
pip install httpx[brotli]  # 包括可选的 brotli 解码器支持

2、 命令行模式


安装: pip install 'httpx[cli]'


现在允许我们直接从命令行使用 HTTPX...

httpx --帮助


发送请求...

httpx http://httpbin.org/json


3、 快速开始


3.1 get请求

import httpx
from fake_useragent import UserAgent
headers = {
    "user-agent": UserAgent().random,
}
params = {
    "wd": "python"  # 输入百度搜索的内容
}
resp = httpx.get("https://www.baidu.com/s", params=params, headers=headers, cookies=None, proxies=None)  # 和原来requests的使用方法类似
resp.encoding = resp.charset_encoding  # 根据文档的编码还对文档进行编码
print(resp.text)  # 获取数据信息

requests中的参数和httpx中的参数大部分类似


3.2 post请求


3.2.1 表单

import httpx
data = {'key1': 'value1', 'key2': 'value2'}
r = httpx.post("https://httpbin.org/post", data=data)
print(r.text)

3.2.2 文件

import httpx
files = {'upload-file': open('a.jpg', 'rb')}
# 也可以通过元组来指定数据类型
# files = {'upload-file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel')}
r = httpx.post("https://httpbin.org/post", files=files)
print(r.text)

3.2.3 JSON

import httpx
data = {'integer': 123, 'boolean': True, 'list': ['a', 'b', 'c']}
r = httpx.post("https://httpbin.org/post", json=data)
print(r.text)

3.2.4 二进制

import httpx
content = b'Hello, world'
r = httpx.post("https://httpbin.org/post", content=content, headers={
    "Content-Type": "application/octet-stream",
})
print(r.text)

Content-Type在上传二进制数据时设置自定义标头

常见的媒体格式类型如下:

  • text/html :HTML格式
  • text/plain :纯文本格式
  • text/xml :XML格式
  • image/gif :gif图片格式
  • image/jpeg :jpg图片格式
  • image/png:png图片格式

以application开头的媒体格式类型:

  • application/xhtml+xml :XHTML格式
  • application/xml:XML数据格式
  • application/atom+xml :Atom XML聚合格式
  • application/json:JSON数据格式
  • application/pdf:pdf格式
  • application/msword :Word文档格式
  • application/octet-stream :二进制流数据(如常见的文件下载)
  • application/x-www-form-urlencoded :
    中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)

另外一种常见的媒体格式是上传文件之时使用的:

  • multipart/form-data :需要在表单中进行文件上传时,就需要使用该格式


3.3 响应处理

import httpx
resp = httpx.request("GET", "https://www.baidu.com")
if resp.status_code == httpx.codes.OK:
    print(resp.text)  # 如果请求成功
print(resp.raise_for_status())  # 判断响应是否成功,成功返回None,失败则报错

3.4 流式响应


对于大型下载,您可能希望使用不会一次将整个响应主体加载到内存中的流式响应。


您可以流式传输响应的二进制内容..

import httpx
with httpx.stream("GET", "https://www.example.com") as r:
    for data in r.iter_bytes():  # 流式传输响应的二进制内容
        # for text in r.iter_text():  # 获取全部的文本内容
        # for line in r.iter_lines():  # 逐行获取传输响应的文本内容
        # for chunk in r.iter_raw():  # 获取编码前的原始数据
        # if r.headers['Content-Length'] < TOO_LONG:  # 有条件的加载内容
        print(data)

注意:

  • 如果您以任何这些方式使用流式响应,则response.contentandresponse.text属性将不可用

3.5 cookie

import httpx
# 获取cookie
r = httpx.get('https://httpbin.org/cookies/set?chocolate=chip')
print(r.cookies['chocolate'])  # 获取请求中的cookie
# 设置cookie
cookies_1 = {"peanut": "butter"}
cookies_2 = httpx.Cookies()
cookies_2.set('cookie_on_domain', 'hello, there!', domain='httpbin.org')
cookies_2.set('cookie_off_domain', 'nope.', domain='example.org')
r = httpx.get('http://httpbin.org/cookies', cookies=cookies_2)
print(r.json())

3.6 重定向


默认情况下,HTTPX不会跟随所有 HTTP 方法的重定向,尽管这可以显式启用。


如,GitHub 将所有 HTTP 请求重定向到 HTTPS。

import httpx
r = httpx.get('http://github.com/')
print(r.status_code)
print(r.history)  # 查看重定向的记录
print(r.next_request)  # 获取到重定向以后的请求对象
resp = httpx.Client().send(r.next_request) # 对请求对象发送请求
print(resp.text)

那么,我们可不可以跟踪这个重定向呢?其实是可以的:


您可以使用参数修改默认重定向处理follow_redirects

import httpx
r = httpx.get('http://github.com/', follow_redirects=True)
print(r.history)  # 查看重定向记录
print(r.url)  # 获取请求的url
print(r.text)  # 获取请求数据

3.7 超时和验证


HTTPX 默认包含所有网络操作的合理超时,这意味着如果连接没有正确建立,那么它应该总是引发错误而不是无限期挂起。


网络不活动的默认超时为五秒。您可以将值修改为或多或少严格:

httpx.get('https://github.com/', timeout=0.001)  # 同时也可以禁止超时行为
httpx.get('https://github.com/', timeout=None)

HTTPX 支持基本和摘要 HTTP 身份验证。


要提供基本身份验证凭据,请将纯文本strbytes对象的 2 元组作为auth参数传递给请求函数:

import httpx
httpx.get("https://example.com", auth=("my_user", "password123"))  # 验证方法一
auth = httpx.DigestAuth("my_user", "password123")  # 验证方法二
httpx.get("https://example.com", auth=auth)

二、 客户端


1、 特性


如果您来自 Requests,httpx.Client()您可以使用它来代替requests.Session().


其功能:


当您使用快速入门指南中记录的顶级 API 发出请求时,HTTPX 必须_为每个请求_建立一个新连接(连接不被重用)。随着对主机的请求数量增加,这很快就会变得低效。


另一方面,Client实例使用HTTP 连接池。这意味着当您向同一主机发出多个请求时,Client将重用底层 TCP 连接,而不是为每个请求重新创建一个。


与使用顶级 API 相比,这可以带来显着的性能提升,包括:

  • 减少请求之间的延迟(无握手)。
  • 减少 CPU 使用率和往返次数。
  • 减少网络拥塞。


额外功能:


Client实例还支持顶级 API 中不可用的功能,例如:

  • 跨请求的 Cookie 持久性。
  • 跨所有传出请求应用配置。
  • 通过 HTTP 代理发送请求。
  • 使用HTTP/2
# 使用方法1
with httpx.Client() as client:
    ...
    
    
# 使用方法2
client = httpx.Client()
try:
    ...
finally:
    client.close()

2、 发出请求


一旦有了,就可以使用,等Client发送请求。例如:.get() .post() ,其传递参数的方法都一样,要注意一点的是,在实例化Client的时候,可以传入请求参数,使得这个局部作用域内可以共享这些参数,跨请求共享配置:

import httpx
# 共用请求头
url = 'http://httpbin.org/headers'
headers = {'user-agent': 'my-app/0.0.1'}
with httpx.Client(headers=headers) as client:
    # 这里面的所有请求的请求头都包含{'user-agent': 'my-app/0.0.1'}
    r = client.get(url)
print(r.json()['headers']['User-Agent'])
# 共用 + 私有
headers = {'X-Auth': 'from-client'}
params = {'client_id': 'client1'}
with httpx.Client(headers=headers, params=params) as client:
    headers_ = {'X-Custom': 'from-request'}
    params_ = {'request_id': 'request1'}
    r = client.get('https://example.com', headers=headers_,
                   params=params_)  # 这个参数结合了headers+headers_ , params+params_,但是只限于params和headers,对于所有其他参数,内部请求级别的值优先
print(r.request.url)
print(r.request.headers['X-Auth'])
print(r.request.headers['X-Custom'])
# 优先级
with httpx.Client(auth=('tom', 'mot123')) as client:
    r = client.get('https://example.com', auth=('alice', 'ecila123'))
_, _, auth = r.request.headers['Authorization'].partition(' ')
import base64
print(base64.b64decode(auth))

3、 其他配置


此外,Client接受一些在请求级别不可用的配置选项。


例如,base_url允许您为所有传出请求添加 URL:

import httpx
with httpx.Client(base_url='http://httpbin.org') as client:
     r = client.get('/headers')
print(r.request.url)

设置编码:

import httpx
import chardet  # pip install chardet
def autodetect(content):
    return chardet.detect(content).get("encoding")  # 对html的编码进行自动的检测
# Using a client with character-set autodetection enabled.
client = httpx.Client(default_encoding=autodetect)
response = client.get(...)
print(response.encoding)  # This will either print the charset given in
                          # the Content-Type charset, or else the auto-detected
                          # character set.
print(response.text)

4、 python web


您可以将httpx客户端配置为使用 WSGI 协议直接调用 Python Web 应用程序。


这对于两个主要用例特别有用:

  • 在测试用例httpx中用作客户端。
  • 在测试期间或在开发/登台环境中模拟外部服务。


下面是一个针对 Flask 应用程序集成的示例:

from flask import Flask
import httpx
app = Flask(__name__)
@app.route("/")
def hello():
    return "Hello World!"
with httpx.Client(app=app, base_url="http://localhost") as client:
    # base_url:指定app的根路由
    r = client.get("/")  # 获取根路由下的响应数据
    print(r.text)
    assert r.status_code == 200  # 断言
    assert r.text == "Hello World!"

对于一些更复杂的情况,您可能需要自定义 WSGI 传输。这使您可以:

  • 通过设置检查 500 个错误响应而不是引发异常raise_app_exceptions=False
  • script_name通过设置(WSGI)将 WSGI 应用程序挂载到子路径。
  • remote_addr通过设置(WSGI)为请求使用给定的客户端地址。
# Instantiate a client that makes WSGI requests with a client IP of "1.2.3.4".
transport = httpx.WSGITransport(app=app, remote_addr="1.2.3.4")
with httpx.Client(transport=transport, base_url="http://testserver") as client:
    ...

5、 Request对象


为了最大限度地控制通过网络发送的内容,HTTPX 支持构建显式Request实例:

request = httpx.Request("GET", "https://example.com")

要将Request实例分派到网络,请创建一个Client实例并使用.send()

with httpx.Client() as client:
    response = client.send(request)
    ...

如果您需要以默认Merging of parameters不支持的方式混合客户端级别和请求级别选项,您可以使用.build_request()然后对Request实例进行任意修改。例如:

headers = {"X-Api-Key": "...", "X-Client-ID": "ABC123"}
with httpx.Client(headers=headers) as client:
    request = client.build_request("GET", "https://api.example.com")
    print(request.headers["X-Client-ID"])  # "ABC123"
    # Don't send the API key for this particular request.
    del request.headers["X-Api-Key"]
    response = client.send(request)
    ...

6、 钩子函数


HTTPX 允许您向客户端注册“事件挂钩”,每次发生特定类型的事件时都会调用这些挂钩。


目前有两个事件挂钩:

  • request- 在请求完全准备好之后,但在它被发送到网络之前调用。通过request实例。
  • response- 在从网络获取响应之后但在返回给调用者之前调用。通过response实例。


这些允许您安装客户端范围的功能,例如日志记录、监视或跟踪。

您还可以使用这些挂钩来安装响应处理代码,例如这个示例,它创建了一个总是httpx.HTTPStatusError 在 4xx 和 5xx 响应时引发的客户端实例。

def raise_on_4xx_5xx(response):
    response.raise_for_status()
client = httpx.Client(event_hooks={'response': [raise_on_4xx_5xx]})

钩子也允许修改requestresponse对象。

def add_timestamp(request):
    request.headers['x-request-timestamp'] = datetime.now(tz=datetime.utc).isoformat()
client = httpx.Client(event_hooks={'request': [add_timestamp]})

事件挂钩必须始终设置为可调用列表,并且您可以为每种类型的事件注册多个事件挂钩。

除了能够在实例化客户端时设置事件挂钩外,还有一个.event_hooks属性允许您检查和修改已安装的挂钩。

client = httpx.Client()
client.event_hooks['request'] = [log_request]
client.event_hooks['response'] = [log_response, raise_on_4xx_5xx]

如果您使用 HTTPX 的异步支持,那么您需要注意注册的钩子httpx.AsyncClient必须是异步函数,而不是普通函数。


7、 进度条


如果您需要监控大型响应的下载进度,您可以使用响应流并检查response.num_bytes_downloaded属性。


此接口是正确确定下载进度所必需的,因为如果使用 HTTP 响应压缩,则返回的总字节数

response.contentresponse.iter_content()不会总是与响应的原始内容长度相对应。


例如,tqdm在下载响应时使用库显示进度条可以这样完成……

import tempfile
import httpx
from tqdm import tqdm
with tempfile.NamedTemporaryFile() as download_file:  # 创建一个临时文件。程序结束就删除
    url = "https://speed.hetzner.de/100MB.bin"
    with httpx.stream("GET", url) as response:  # 使用流发送请求
        total = int(response.headers["Content-Length"])
        with tqdm(total=total, unit_scale=True, unit_divisor=1024, unit="B") as progress:
            num_bytes_downloaded = response.num_bytes_downloaded
            for chunk in response.iter_bytes():
                download_file.write(chunk)
                progress.update(response.num_bytes_downloaded - num_bytes_downloaded)
                num_bytes_downloaded = response.num_bytes_downloaded

8、 .netrc 支持


HTTPX 支持 .netrc 文件。在trust_env=True某些情况下,如果未定义 auth 参数,HTTPX 会尝试将 auth 从 .netrc 文件添加到请求的标头中。

NETRC 文件在客户端发出的请求之间进行缓存。如果您需要刷新缓存(例如,因为 NETRC 文件已更改),您应该创建一个新客户端或重新启动解释器。

默认trust_env为真。设置为假:

httpx.get('https://example.org/', trust_env=False)

如果NETRCenvironment 为空,HTTPX 会尝试使用默认文件。( ~/.netrc, ~/_netrc)


改变NETRC环境:

import os
os.environ["NETRC"] = "my_default_folder/.my_netrc"

.netrc 文件内容示例:

machine netrcexample.org
login example-username
password example-password
...

使用Client实例时,trust_env应该在客户端本身上设置,而不是在请求方法上:

client = httpx.Client(trust_env=False)


Python3 新一代Http请求库Httpx使用(详情版)(下):https://developer.aliyun.com/article/1462936?spm=a2c6h.13148508.setting.31.7b614f0eGbArf0


相关文章
|
25天前
|
JSON API 数据格式
Python中获取HTTP请求响应体的详解
本文介绍了如何使用Python的`requests`和`urllib`库发送HTTP请求并处理响应体。`requests`库简化了HTTP请求过程,适合快速开发;`urllib`库则更为底层,适用于性能要求较高的场景。文章详细演示了发送GET请求、处理JSON响应等常见操作。
38 3
|
6天前
|
Web App开发 网络安全 数据安全/隐私保护
Lua中实现HTTP请求的User-Agent自定义
Lua中实现HTTP请求的User-Agent自定义
|
1月前
|
前端开发 JavaScript Java
如何捕获和处理HTTP GET请求的异常
如何捕获和处理HTTP GET请求的异常
|
1月前
|
开发者
HTTP 协议请求方法的发展历程
【10月更文挑战第21天】
|
1月前
|
缓存 安全 前端开发
HTTP 协议的请求方法在实际应用中有哪些注意事项?
【10月更文挑战第29天】HTTP协议的请求方法在实际应用中需要根据具体的业务场景和需求,合理选择和使用,并注意各种方法的特点和限制,以确保网络通信的安全、高效和数据的一致性。
|
开发者 Python
根据不同的请求返回不同的内容 | 手把手教你入门Python之一百一十二
本节实现根据不同的请求返回不同的内容,使浏览器访问 /register 或 /login 使返回不同的内容。
根据不同的请求返回不同的内容 | 手把手教你入门Python之一百一十二
|
18天前
|
存储 数据挖掘 开发者
Python编程入门:从零到英雄
在这篇文章中,我们将一起踏上Python编程的奇幻之旅。无论你是编程新手,还是希望拓展技能的开发者,本教程都将为你提供一条清晰的道路,引导你从基础语法走向实际应用。通过精心设计的代码示例和练习,你将学会如何用Python解决实际问题,并准备好迎接更复杂的编程挑战。让我们一起探索这个强大的语言,开启你的编程生涯吧!
|
24天前
|
机器学习/深度学习 人工智能 TensorFlow
人工智能浪潮下的自我修养:从Python编程入门到深度学习实践
【10月更文挑战第39天】本文旨在为初学者提供一条清晰的道路,从Python基础语法的掌握到深度学习领域的探索。我们将通过简明扼要的语言和实际代码示例,引导读者逐步构建起对人工智能技术的理解和应用能力。文章不仅涵盖Python编程的基础,还将深入探讨深度学习的核心概念、工具和实战技巧,帮助读者在AI的浪潮中找到自己的位置。
|
24天前
|
机器学习/深度学习 数据挖掘 Python
Python编程入门——从零开始构建你的第一个程序
【10月更文挑战第39天】本文将带你走进Python的世界,通过简单易懂的语言和实际的代码示例,让你快速掌握Python的基础语法。无论你是编程新手还是想学习新语言的老手,这篇文章都能为你提供有价值的信息。我们将从变量、数据类型、控制结构等基本概念入手,逐步过渡到函数、模块等高级特性,最后通过一个综合示例来巩固所学知识。让我们一起开启Python编程之旅吧!
|
24天前
|
存储 Python
Python编程入门:打造你的第一个程序
【10月更文挑战第39天】在数字时代的浪潮中,掌握编程技能如同掌握了一门新时代的语言。本文将引导你步入Python编程的奇妙世界,从零基础出发,一步步构建你的第一个程序。我们将探索编程的基本概念,通过简单示例理解变量、数据类型和控制结构,最终实现一个简单的猜数字游戏。这不仅是一段代码的旅程,更是逻辑思维和问题解决能力的锻炼之旅。准备好了吗?让我们开始吧!