【问题标题】:How to retry urllib2.request when fails?失败时如何重试 urllib2.request?
【发布时间】:2012-03-15 19:49:42
【问题描述】:

当urllib2.request 超时时,会引发urllib2.URLError 异常。 重试建立连接的pythonic方法是什么?

【问题讨论】:

  • 这个问题应该回答你的问题:stackoverflow.com/questions/2712524/…
  • 我没有问如何抓住期望。我想知道是否有pythonic方法来重试建立连接。
  • 对不起,我认为问题在于检测到超时,而不是重新建立连接。不能在异常块中调用 urlopen() 吗?
  • 这是可能的,但似乎不是很pythonic。如果我想重试 3 次,我将不得不嵌套 try-except 块,而且看起来很难看。
  • 这可能会有所帮助:stackoverflow.com/questions/567622/…

标签: python decorator urllib2 urllib3


【解决方案1】:

我会使用 retry 装饰器。那里还有其他的,但是这个很好用。使用方法如下:

@retry(urllib2.URLError, tries=4, delay=3, backoff=2)
def urlopen_with_retry():
    return urllib2.urlopen("http://example.com")

如果引发URLError,这将重试该函数。检查上面的链接以获取有关参数的文档,但基本上它将重试最多 4 次,每次指数退避延迟加倍,例如3 秒、6 秒、12 秒。

【讨论】:

  • 这是一个非常酷的 sn-p。您知道替代方案吗,但作为上下文管理器?
  • 嗯,我想你可以很容易地将它重写为上下文管理器,但我没有一个临时的。
  • 这并不容易,因为没有简单的方法来捕获 with 语句中的块。你需要一些深刻的反省。
  • 不,我认为这不是真的。在 yield 之后,异常会在上下文管理器中重新引发。
  • 问题不在于异常,而在于引发异常的代码。如果无法运行代码,如何重试代码? Python 中没有匿名块的概念。这是可行的,但不直观。
【解决方案2】:

要重试超时,您可以将异常捕获为@Karl Barker suggested in the comment:

assert ntries >= 1
for _ in range(ntries):
    try:
        page = urlopen(request, timeout=timeout)
        break # success
    except URLError as err:
        if not isinstance(err.reason, socket.timeout):
           raise # propagate non-timeout errors
else: # all ntries failed 
    raise err # re-raise the last timeout error
# use page here

【讨论】:

    【解决方案3】:

    有一些专门研究这个的库。

    一个是backoff,它的设计具有特别的功能敏感性。装饰器被传递任意可调用的返回生成器,这些生成器产生连续的延迟值。最大重试时间为 32 秒的简单指数退避可以定义为:

    @backoff.on_exception(backoff.expo,
                          urllib2.URLError,
                          max_value=32)
    def url_open(url):
        return urllib2.urlopen("http://example.com")
    

    另一个是retrying,它具有非常相似的功能,但通过预定义的关键字 args 指定重试参数的 API。

    【讨论】:

      【解决方案4】:

      对于 Python3:

      from urllib3 import Retry, PoolManager
      
      
      retries = Retry(connect=5, read=2, redirect=5, backoff_factor=0.1)
      http = PoolManager(retries=retries)
      response = http.request('GET', 'http://example.com/')
      

      如果 backoff_factor 为 0.1,则 :func:.sleep 将休眠 重试之间的 [0.0s, 0.2s, 0.4s, ...]。它永远不会更长 比:attr:Retry.BACKOFF_MAX。 urllib3 将休眠::

              {backoff factor} * (2 ** ({number of total retries} - 1))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-11-18
        • 2017-01-01
        • 1970-01-01
        • 2011-06-01
        • 1970-01-01
        • 1970-01-01
        • 2022-06-14
        相关资源
        最近更新 更多