Skip to main content

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方法,所以对你的paramsbodyheadersauth等 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 调用

项目详情


下载文件

下载适用于您平台的文件。如果您不确定要选择哪个,请了解有关安装包的更多信息。

源分布

requests-respectful-0.2.0.tar.gz (12.0 kB 查看哈希)

已上传 source