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

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秒后进入超时,这样循环就不会卡住。

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

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


当前回答

如果遇到这种情况,创建一个看门狗线程,在10秒后搞乱请求的内部状态,例如:

关闭底层套接字,理想情况下 如果请求重试该操作,则触发异常

请注意,根据系统库的不同,您可能无法设置DNS解析的截止日期。

其他回答

只是另一个解决方案(从http://docs.python-requests.org/en/master/user/advanced/#streaming-uploads获得)

在上传之前,你可以找出内容大小:

TOO_LONG = 10*1024*1024  # 10 Mb
big_url = "http://ipv4.download.thinkbroadband.com/1GB.zip"
r = requests.get(big_url, stream=True)
print (r.headers['content-length'])
# 1073741824  

if int(r.headers['content-length']) < TOO_LONG:
    # upload content:
    content = r.content

但是要小心,发送方可以在“content-length”响应字段中设置不正确的值。

有一个叫做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))

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

我相信你可以使用多处理,而不依赖于第三方包:

import multiprocessing
import requests

def call_with_timeout(func, args, kwargs, timeout):
    manager = multiprocessing.Manager()
    return_dict = manager.dict()

    # define a wrapper of `return_dict` to store the result.
    def function(return_dict):
        return_dict['value'] = func(*args, **kwargs)

    p = multiprocessing.Process(target=function, args=(return_dict,))
    p.start()

    # Force a max. `timeout` or wait for the process to finish
    p.join(timeout)

    # If thread is still active, it didn't finish: raise TimeoutError
    if p.is_alive():
        p.terminate()
        p.join()
        raise TimeoutError
    else:
        return return_dict['value']

call_with_timeout(requests.get, args=(url,), kwargs={'timeout': 10}, timeout=60)

传递给kwargs的超时是从服务器获取任何响应的超时,参数timeout是获取完整响应的超时。

使用eventlet怎么样?如果你想在10秒后超时请求,即使数据正在接收,下面的代码段将为你工作:

import requests
import eventlet
eventlet.monkey_patch()

with eventlet.Timeout(10):
    requests.get("http://ipv4.download.thinkbroadband.com/1GB.zip", verify=False)

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

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

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