我正在收集网站列表上的统计数据,为了简单起见,我正在使用请求。这是我的代码:

data=[]
websites=['http://google.com', 'http://bbc.co.uk']
for w in websites:
    r= requests.get(w, verify=False)
    data.append( (r.url, len(r.content), r.elapsed.total_seconds(), str([(l.status_code, l.url) for l in r.history]), str(r.headers.items()), str(r.cookies.items())) )
 

现在,我想要请求。10秒后进入超时,这样循环就不会卡住。

这个问题以前也很有趣,但没有一个答案是干净的。

我听说可能不使用请求是一个好主意,但我应该如何得到请求提供的好东西(元组中的那些)。


当前回答

连接超时是请求等待客户端建立到远程机器的连接(对应于套接字上的connect()调用)的秒数。将连接超时设置为略大于3的倍数是一个很好的实践,3是默认的TCP数据包重传窗口。

一旦客户端连接到服务器并发送了HTTP请求,读超时就开始了。它是客户端等待服务器发送响应的秒数。(具体来说,它是客户端在从服务器发送字节之间等待的秒数。在99.9%的情况下,这是服务器发送第一个字节之前的时间)。

如果您为超时指定了一个值,则该超时值将应用于连接超时和读取超时。像下图:

r = requests.get('https://github.com', timeout=5)

如果你想分别设置connect和read的值,请指定一个元组:

r = requests.get('https://github.com', timeout=(3.05, 27))

如果远程服务器非常慢,您可以告诉Requests永远等待响应,方法是将None作为超时值,然后检索一杯咖啡。

r = requests.get('https://github.com', timeout=None)

https://docs.python-requests.org/en/latest/user/advanced/#timeouts

其他回答

这可能有点过分,但是芹菜分布式任务队列对超时有很好的支持。

特别是,您可以定义一个软时间限制,它只在您的流程中引发一个异常(这样您就可以清理)和/或一个硬时间限制,它在超过时间限制时终止任务。

在封面之下,这使用了与你的“之前”帖子中引用的相同的信号方法,但以一种更可用和更易于管理的方式。如果你监控的网站列表很长,你可能会从它的主要功能中受益——各种各样的方法来管理大量任务的执行。

尽管问题是关于请求的,但我发现使用pycurl CURLOPT_TIMEOUT或CURLOPT_TIMEOUT_MS很容易做到这一点。

不需要线程或信号:

import pycurl
import StringIO

url = 'http://www.example.com/example.zip'
timeout_ms = 1000
raw = StringIO.StringIO()
c = pycurl.Curl()
c.setopt(pycurl.TIMEOUT_MS, timeout_ms)  # total timeout in milliseconds
c.setopt(pycurl.WRITEFUNCTION, raw.write)
c.setopt(pycurl.NOSIGNAL, 1)
c.setopt(pycurl.URL, url)
c.setopt(pycurl.HTTPGET, 1)
try:
    c.perform()
except pycurl.error:
    traceback.print_exc() # error generated on timeout
    pass # or just pass if you don't want to print the error

有一个叫做timeout-decorator的包,你可以用它让任何python函数超时。

@timeout_decorator.timeout(5)
def mytest():
    print("Start")
    for i in range(1,10):
        time.sleep(1)
        print("{} seconds have passed".format(i))

它使用这里的一些答案所建议的信号方法。或者,你可以告诉它使用多处理而不是信号(例如,如果你在多线程环境中)。

我使用请求2.2.1和eventlet不适合我。相反,我可以使用gevent超时代替,因为gevent在我的服务中用于gunicorn。

import gevent
import gevent.monkey
gevent.monkey.patch_all(subprocess=True)
try:
    with gevent.Timeout(5):
        ret = requests.get(url)
        print ret.status_code, ret.content
except gevent.timeout.Timeout as e:
    print "timeout: {}".format(e.message)

请注意geevent .timeout. timeout不会被常规异常处理捕获。 所以要么显式地捕获getevent。timeout。timeout 或者传入一个不同的异常,像这样使用:with gevent。Timeout(5, requests.exceptions.Timeout):尽管在引发此异常时没有传递任何消息。

Timeout = int(秒)

由于请求>= 2.4.0,您可以使用timeout参数,即:

requests.get('https://duckduckgo.com/', timeout=10)

注意:

Timeout不是整个响应下载的时间限制;相反, 如果服务器没有发出响应,则会引发异常 超时秒(更准确地说,如果在 底层套接字超时秒)。如果未指定超时时间 显然,请求不会超时。