Requests 之上的极简主义包装器,可同时在任意数量的服务的速率限制内工作。并行处理友好。
项目描述
如果你了解 Python,你就会知道 `Requests <http://docs.python-requests.org/>`__。要求就是爱。 请求就是生命。根据您的用例,您可能会遇到需要大量使用请求的场景。您使用的服务可能有限速政策,或者您可能恰好心情好,感觉自己是一个好网民。这就是 请求尊重可以派上用场的地方。
*请求尊重*:
是Requests之上的简约包装器,可同时在任意数量的服务的速率限制内工作
可以横向扩展单线程、单进程甚至单机
允许最大化您的允许请求,而不会超过设定的限制并且不必处理后果
代理请求HTTP 动词方法(用于最小的代码更改)
适用于 Python 2 和 3 并经过全面测试
很酷(希望?)
典型的*请求*调用
import requests
response = requests.get("http://github.com", params={"foo": "bar"})
魔术 *requests-respectful* 调用-请求动词方法被代理!
from requests_respectful import RespectfulRequester
rr = RespectfulRequester()
# This can be done elsewhere but the realm needs to be registered!
rr.register_realm("Github", max_requests=100, timespan=60)
response = rr.get("http://github.com", params={"foo": "bar"}, realms=["Github"], wait=True)
保守的 *requests-respectful* 调用- 通过请求方法调用传递 lambda
import requests
from requests_respectful import RespectfulRequester
rr = RespectfulRequester()
# This can be done elsewhere but the realm needs to be registered!
rr.register_realm("Github", max_requests=100, timespan=60)
request_func = lambda: requests.get("http://github.com", params={"foo": "bar"})
response = rr.request(request_func, realms=["Github"], wait=True)
要求
Redis > 2.8.0(如果你翻白眼,请参阅常见问题解答)
安装
pip install requests-respectful
配置
默认配置值
{
"redis": {
"host": "localhost",
"port": 6379,
"database": 0
},
"safety_threshold": 10,
"requests_module_name": "requests"
}
配置键
redis : 提供Redis 实例的主机、端口和数据库
safety_threshold:将在 (realm_max_requests - safety_threshold)处引发速率限制异常。防止在大量请求并行发出的场景中超出服务限制
requests_module_name:提供 请求 lambda 中使用的请求模块的名称。除非您将Requests作为另一个名称导入,否则不需要更改。
覆盖配置值
使用requests-respectful.config.yml
该库会自动检测项目根目录中是否存在名为 requests-respectful.config.yml的 YAML 文件,并将尝试从中加载配置值。
示例:
请求尊重.config.yml
redis:
host: 0.0.0.0
port: 6379
database: 5
safety_threshold: 25
使用configure()类方法
如果您不喜欢有多余的文件,也可以在运行时使用configure()类方法配置该库。
RespectfulRequester.configure(
redis={"host": "0.0.0.0", "port": 6379, "database": 5},
safety_threshold=25
)
在这两种情况下,生成的活动配置将是:
RespectfulRequester._config()
Out[1]: {
"redis": {
"host": "0.0.0.0",
"port": 6379,
"database": 5
},
"safety_threshold": 25,
"requests_module_name": "requests"
}
用法
在你使用requests-respectful 的过程中,你应该只需要关心一个类:RespectfulRequester。实例化此类,您可以执行所有重要操作。
在每个示例之前,假设已经执行了以下代码。
from requests_respectful import RespectfulRequester
rr = RespectfulRequester()
领域
领域只是以最大请求速率提供的简单命名容器。您负责您的领域的管理(即 CRUD)。
领域跟踪在它们下执行的 HTTP 请求,如果您超过其允许的请求速率,将引发可捕获的速率限制异常。
获取领域列表
rr.fetch_registered_realms()
这将返回当前注册的域名列表。
注册领域
rr.register_realm("Google", max_requests=10, timespan=1)
rr.register_realm("Github", max_requests=100, timespan=60)
rr.register_realm("Twitter", max_requests=150, timespan=300)
# OR
realm_tuples = [
["Google", 10, 1],
["Github", 100, 60],
["Twitter", 150, 300]
]
rr.register_realms(realm_tuples)
其中任何一个注册 3 个领域: * Google的最大请求率为每秒 10 个请求 * Github的最大请求率为每分钟 100 个请求 * Twitter的最大请求率为每 5 分钟 150 个请求
更新领域
rr.update_realm("Google", max_requests=25, timespan=5)
这会将Google的最大请求速率更新为每 5 秒 25 个请求。
获取 Realm 的最大请求值
rr.realm_max_requests("Google")
这将返回 25。
获取领域的时间跨度值
rr.realm_timespan("Google")
这将返回 5。
注销领域
rr.unregister_realm("Google")
这将取消注册Google领域,从而阻止在其上执行进一步的查询。
注销多个领域
rr.unregister_realms(["Google", "Github", "Twitter"])
这将在一次操作中取消注册所有 3 个领域,从而阻止对它们执行进一步的查询。
请求
使用Requests HTTP 动词方法
该库支持对 7 种请求HTTP 动词方法(DELETE、GET、HEAD、OPTIONS、PATCH、POST、PUT)的代理调用。这实际上是一个Requests方法,所以对你的params、body、 headers、auth等 kwargs发疯。唯一的主要区别是需要一个 领域kwarg。还可以提供等待布尔 kwargs(行为稍后解释)。
这些都是有效的调用:
rr.get("http://httpbin.org", realms=["HTTPBin"])
rr.post('http://httpbin.org/post', data = {'key':'value'}, realms=["HTTPBin"], wait=True)
rr.put('http://httpbin.org/put', data = {'key':'value'}, realms=["HTTPBin"])
rr.delete('http://httpbin.org/delete', realms=["HTTPBin"])
如果没有速率限制,这些将返回您通常的requests.Response 对象。
使用请求 Lamba
如果你是一个纯粹主义者并且不喜欢使用花哨的代理,你也可以创建一个你的Requests调用的 lambda 并将它传递给 request()实例方法。
request_func = lambda: requests.post('http://httpbin.org/post', data = {'key':'value'})
rr.request(request_func, realms=["HTTPBin"], wait=True)
如果没有速率限制,这将返回您通常的requests.Response 对象。
每个请求多个领域
从 0.2.0 开始,您可以对多个领域进行单个请求计数。kwarg 已从一个领域更改为另一个领域,并且可以按照您的预期工作。
rr.get("http://httpbin.org", realms=["HTTPBin", "HTTPBinUser123", "HTTPBinServer3"])
在请求实例方法时,不推荐使用kwarg领域。在 0.3.0 之前它仍然会发出警告
处理异常
执行这些调用将返回带有 HTTP 调用结果的requests.Response对象或引发 RequestsRespectfulRateLimitedError 异常。这意味着您可能希望捕获并处理该异常。
from requests_respectful import RequestsRespectfulRateLimitedError
try:
response = rr.get("http://httpbin.org", realm="HTTPBin")
except RequestsRespectfulRateLimitedError:
pass # Possibly requeue that call or wait.
等待夸格
两种请求方式都接受默认为 False 的wait kwarg。如果打开并且领域当前是速率限制的,则该进程将阻塞,等到再次发送请求安全后再执行请求。等待对于脚本或较小的操作来说非常好,但对于大型、多领域、并行任务(即后台任务,如 Celery 工作人员)不鼓励。
测试
存在?是的
详尽无遗?是的
打脸战术? 是的 - Redis 调用不会被模拟,并且 google.com 会收到一些友好的调用
使用python -m pytest tests --spec运行它们
常问问题
哇哇哇哇!雷迪斯?!
是的。Redis 的使用允许尊重请求的多线程、多进程甚至多机器,同时仍然尊重注册领域的最大请求率。Redis 的 SETEX 等操作是设计和使用速率限制系统的关键。如果您正在进行 Python 开发,那么您很有可能已经在使用 Redis,因为它是用作 Celery 后端的两个选项之一,也是 Web 开发中的两个主要缓存选项之一。如果没有,您可以始终保持清洁并使用Docker 容器,甚至从源代码构建它。多年来,Redis 一直保持着作为轻量级、可靠软件的一贯记录。
这与其他节流库有何不同?
大多数其他库会要求您指定发送请求的时间间隔,并且会逐字地循环 request()...time.sleep(interval)。只要您在您的领域的最大请求率以下,这将允许您发送尽可能多的发送。
其他库没有领域的概念和单独的请求率规则。
其他库不会在流程之外扩展。
大多数其他库都没有将它与请求巧妙地集成
路线图/贡献想法
提供一些自省方法来获取实时领域统计信息
创建一个 curses 领域统计信息监视器
提供真实的用例
阅读文档 RST 文档
在测试中模拟 Redis 调用
在测试中模拟 Requests 调用