【问题标题】:Python urllib2 does not respect timeoutPython urllib2 不遵守超时
【发布时间】:2015-02-04 07:48:42
【问题描述】:

以下两行代码永远挂起:

import urllib2
urllib2.urlopen('https://www.5giay.vn/', timeout=5)

这是使用 python2.7 的,我没有设置 http_proxy 或任何其他 env 变量。任何其他网站都可以正常工作。我也可以毫无问题地获得该网站。可能是什么问题?

【问题讨论】:

  • 我在 Linux (Amazon AMI) 和 Mac OS 上都看到了这一点。此外,似乎与 DNS 无关,因为即使这样也会挂起: urllib2.urlopen('210.245.123.158', timeout=1)

标签: python-2.7 urllib2


【解决方案1】:

如果你跑了

import urllib2

url = 'https://www.5giay.vn/'
urllib2.urlopen(url, timeout=1.0)

等待几秒,然后用C-c中断程序,你会看到

  File "/usr/lib/python2.7/ssl.py", line 260, in read
    return self._sslobj.read(len)
KeyboardInterrupt

这说明程序挂在self._sslobj.read(len)上。

SSL timeouts raise socket.timeout.

您可以通过调用来控制引发 socket.timeout 之前的延迟 socket.setdefaulttimeout(1.0).

例如,

import urllib2
import socket

socket.setdefaulttimeout(1.0)
url = 'https://www.5giay.vn/'
try:
    urllib2.urlopen(url, timeout=1.0)
except IOError as err:
    print('timeout')

% time script.py
timeout

real    0m3.629s
user    0m0.020s
sys 0m0.024s

请注意,the requests module 在这里成功,尽管 urllib2 没有:

import requests
r = requests.get('https://www.5giay.vn/')

如何对整个函数调用强制超时:

socket.setdefaulttimeout 仅影响 Python 在引发异常之前等待的时间如果服务器没有发出响应

它和urlopen(..., timeout=...) 都没有对整个函数调用实施时间限制。

为此,您可以使用 eventlet,as shown here

如果你不想安装eventlets,你可以使用标准库中的multiprocessing;尽管此解决方案的扩展性不如 eventlets 提供的异步解决方案。

import urllib2
import socket
import multiprocessing as mp

def timeout(t, cmd, *args, **kwds):
    pool = mp.Pool(processes=1)
    result = pool.apply_async(cmd, args=args, kwds=kwds)
    try:
        retval = result.get(timeout=t)
    except mp.TimeoutError as err:
        pool.terminate()
        pool.join()
        raise
    else:
        return retval

def open(url):
    response = urllib2.urlopen(url)
    print(response)

url = 'https://www.5giay.vn/'
try:
    timeout(5, open, url)
except mp.TimeoutError as err:
    print('timeout')

运行此程序将在挂钟时间约 5 秒后成功或超时。

【讨论】:

  • 感谢您的调查。超时时间为 1,它确实超时。但是如果你设置 timeout=5.0,它就会永远挂起。奇怪!
  • 谢谢,在这种情况下,网络服务器配置错误,每秒发送 1 个字符。所以超时没有达到,但请求仍然需要永远。
猜你喜欢
  • 2020-04-04
  • 1970-01-01
  • 2015-09-14
  • 1970-01-01
  • 2020-05-02
  • 2020-07-18
  • 2018-03-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多