当前位置: 首页 > 工具软件 > Python plog > 使用案例 >

pythonrequests设置_关于python:我可以为requests.request设置max_retries吗?

严开宇
2023-12-01

Python请求模块简单而优雅,但有一点让我感到困惑。

可以使用以下消息获取requests.exception.ConnectionError:

Max retries exceeded with url: ...

这意味着请求可以尝试多次访问数据。 但是在文档的任何地方都没有提到这种可能性。 看看源代码,我找不到任何可以改变默认值(大概为0)的地方。

那么有可能以某种方式设置请求的最大重试次数吗?

对2.x的请求有任何更新吗? 非常喜欢requests.get(url,max_retries = num_max_retries))实现。

@paragbaxi:甚至更好的requests.get(url, max_retries=num_max_retries, dely_between_retries=3))

使用urllib3查看我的重试和退避策略的答案。

@WoJ我把你的例子变成现实;)在github.com/kootenpv/just中的just.get和just.post

有关使用请求重试的有用文章:peterbe.com/plog/best-practice-with-retries-with-requests

这不仅会更改max_retries,还会启用退避策略,该策略会在重试之前使所有http://地址的请求休眠一段时间(总共5次):

import requests

from urllib3.util.retry import Retry

from requests.adapters import HTTPAdapter

s = requests.Session()

retries = Retry(total=5,

backoff_factor=0.1,

status_forcelist=[ 500, 502, 503, 504 ])

s.mount('http://', HTTPAdapter(max_retries=retries))

s.get('http://httpstat.us/500')

根据Retry的文档:如果backoff_factor为0.1,则sleep()将在重试之间休眠[0.1s,0.2s,0.4s,...]。如果返回的状态代码为500,502,503或504,它也会强制重试。

Retry的各种其他选项允许更精细的控制:

total - 允许的重试总次数。

connect - 要重试的与连接相关的错误数。

读取 - 重试读取错误的次数。

重定向 - 要执行的重定向数。

method_whitelist - 我们应该重试的大写HTTP方法动词集。

status_forcelist - 我们应该强制重试的一组HTTP状态代码。

backoff_factor - 在尝试之间应用的退避因子。

raise_on_redirect - 是否,如果重定向的数量已用尽,则引发MaxRetryError,或返回响应代码在3xx范围内的响应。

raise_on_status - 与raise_on_redirect类似的意思:如果状态落在status_forcelist范围内并且重试已经用尽,我们是应该引发异常还是返回响应。

注意:raise_on_status是相对较新的,并且尚未将其发送到urllib3或请求版本。 strike> raise_on_status关键字参数似乎最多在python版本3.6中进入标准库。

要使请求在特定HTTP状态代码上重试,请使用status_forcelist。例如,status_forcelist = [503]将在状态码503(服务不可用)上重试。

默认情况下,重试仅针对以下条件触发:

无法从池中获得连接。

TimeoutError

HTTPException引发(来自Python 3中的http.client,否则为httplib)。

这似乎是低级HTTP异常,如URL或协议

形成正确。

SocketError

ProtocolError

请注意,这些都是阻止接收常规HTTP响应的异常。如果生成任何常规响应,则不会重试。如果不使用status_forcelist,即使状态为500的响应也不会被重试。

为了使其能够以更直观的方式使用远程API或Web服务器,我将使用上面的代码片段,它强制重试状态500,502,503和504,所有这些都不常见于在足够大的退避期间,网络和(可能)可恢复。

编辑:直接从urllib3导入Retry类。

我正在尝试实现你的逻辑,但我不知道它是否正常工作,因为日志只显示一个请求,即使res状态是503.我怎么知道重试是否有效?请参阅代码:pastebin.com/rty4bKTw

附加的代码按预期工作。技巧是status_forcelist参数。这告诉urllib3包重试特定的状态代码。代码:pastebin.com/k2bFbH7Z

urllib3没有(也不应该)认为状态503是一个例外(默认情况下)。

这是否适用于非会话操作(例如requests.post()?)

@Connor不,适配器已附加到会话中。

urlib3.Retry不再是请求的一部分。这必须直接导入。建议编辑

@ user2390183感谢指针,编辑。

它是基础urllib3库进行重试。要设置不同的最大重试计数,请使用备用传输适配器:

from requests.adapters import HTTPAdapter

s = requests.Session()

s.mount('http://stackoverflow.com', HTTPAdapter(max_retries=5))

max_retries参数采用整数或Retry()对象;后者使您可以对重试的类型失败进行细粒度控制(整数值转换为仅处理连接失败的Retry()实例;默认情况下不会处理连接后的错误,因为这些错误可能会导致效果 - )。

旧的答案,早于请求的发布1.2.1:

requests库并没有真正使这个可配置,也没有打算(参见这个拉取请求)。当前(请求1.1),重试次数设置为0.如果您确实要将其设置为更高的值,则必须全局设置:

import requests

requests.adapters.DEFAULT_RETRIES = 5

这个常数没有记录;因为未来版本可能会改变处理方式,所以使用它会让您自担风险。

更新:这确实改变了;在版本1.2.1中添加了在HTTPAdapter()类上设置max_retries参数的选项,因此现在您必须使用备用传输适配器,请参阅上文。猴子补丁方法不再有效,除非您还修补HTTPAdapter.__init__()默认值(非常不推荐)。

如果不需要,您不必为每个站点指定此项。您可以执行session.mount('http://', HTTPAdapter(max_retries=10))这适用于所有http连接。与https相同的功能将适用于所有https连接。

@ user136036:是的,通过最长前缀匹配查找适配器;如果要将其应用于所有URL,则http://和https://是要使用的最小前缀,请参阅答案所链接的文档。

请注意,HTTPAdapter(max_retries=5)仅适用于特定方案。来自请求doc,Note, this applies only to failed DNS lookups, socket connections and connection timeouts, never to requests where data has made it to the server. By default, Requests does not retry failed connections.要强制重试任何状态代码,请参阅下面的@ datashaman的答案。

@StevenXu:是的,您可以配置Retry()来更改重试的故障情况。

小心,Martijn Pieters的答案不适合1.2.1+版本。如果不修补库,则无法全局设置。

你可以这样做:

import requests

from requests.adapters import HTTPAdapter

s = requests.Session()

s.mount('http://www.github.com', HTTPAdapter(max_retries=5))

s.mount('https://www.github.com', HTTPAdapter(max_retries=5))

很好的解决方案,但请注意重试之间没有延迟。如果你想在尝试之间睡觉,你需要自己动手。

在对这里的一些答案进行了一些努力之后,我找到了一个名为backoff的库,它对我的情况更有效。 一个基本的例子:

import backoff

@backoff.on_exception(

backoff.expo,

requests.exceptions.RequestException,

max_tries=5,

giveup=lambda e: e.response is not None and e.response.status_code < 500

)

def publish(self, data):

r = requests.post(url, timeout=10, json=data)

r.raise_for_status()

我仍然建议尽快给出库的本机功能,但如果遇到任何问题或需要更广泛的控制,退避是一种选择。

很棒的图书馆,谢谢!除了requests之外我还需要这个功能,所以这非常有效!

获得更高控制的更简洁方法可能是将重试内容打包到函数中,并使用装饰器使该函数可重复,并将异常列入白名单。

我在这里创建了同样的东西:

重现该链接中的代码:

def retry(exceptions, delay=0, times=2):

"""

A decorator for retrying a function call with a specified delay in case of a set of exceptions

Parameter List

-------------

:param exceptions:  A tuple of all exceptions that need to be caught for retry

e.g. retry(exception_list = (Timeout, Readtimeout))

:param delay: Amount of delay (seconds) needed between successive retries.

:param times: no of times the function should be retried

"""

def outer_wrapper(function):

@functools.wraps(function)

def inner_wrapper(*args, **kwargs):

final_excep = None

for counter in xrange(times):

if counter > 0:

time.sleep(delay)

final_excep = None

try:

value = function(*args, **kwargs)

return value

except (exceptions) as e:

final_excep = e

pass #or log it

if final_excep is not None:

raise final_excep

return inner_wrapper

return outer_wrapper

@retry(exceptions=(TimeoutError, ConnectTimeoutError), delay=0, times=3)

def call_api():

while page is None:

try:

page = requests.get(url, timeout=5,proxies=proxies)

except Exception:

page = None

说实话,你错过了问题的重点。

 类似资料: