如何使用Python的requests库执行有时间限制的响应下载?

17 浏览
0 Comments

如何使用Python的requests库执行有时间限制的响应下载?

在使用Python下载大文件时,我希望不仅对连接过程设置时间限制,还对下载过程设置时间限制。\n我正在尝试以下Python代码:\n

import requests
r = requests.get('http://ipv4.download.thinkbroadband.com/1GB.zip', timeout=0.5, prefetch=False)
print(r.headers['content-length'])
print(len(r.raw.read()))

\n这个代码不起作用(下载没有时间限制),正如文档中正确指出的那样:https://requests.readthedocs.org/en/latest/user/quickstart/#timeouts\n如果可能的话,这将是很好的:\n

r.raw.read(timeout=10)

\n问题是,如何对下载设置时间限制?

0
0 Comments

如何使用Python的requests库进行限时响应下载?

问题的原因:

- 使用线程运行下载操作,如果在规定时间内未完成,则可以中止。

解决方法:

import requests
import threading
URL = 'http://ipv4.download.thinkbroadband.com/1GB.zip'
TIMEOUT = 0.5
def download(return_value):
    return_value.append(requests.get(URL))
return_value = []
download_thread = threading.Thread(target=download, args=(return_value,))
download_thread.start()
download_thread.join(TIMEOUT)
if download_thread.is_alive():
    print('The download was not finished on time...')
else:
    print(return_value[0].headers['content-length'])

然而,这种方法不是一个安全的方式。Python的线程存在问题,并且不能在超时时直接终止线程,这不是一个干净的解决方案。

如果愿意,可以将线程替换为进程。为什么不能直接终止线程?

"在Python和任何其他语言中,直接终止线程通常是一种不好的模式。" [stackoverflow.com/a/325528/389463](http://stackoverflow.com/a/325528/389463) 无法告诉线程停止。

使用进程过于复杂,需要进行进程间通信。

使用这段代码时,当超时触发时会发生什么?线程可能永远存在,没有人停止它。如果同时进行多个下载,这将导致线程数爆炸。

是的,但是你可以切换到multiprocessing模块,然后使用Process.terminate()来终止下载进程。然而,如果有多个下载任务,使用异步方法和gevent级别上的超时可能更好。

实际上,线程无法在Python中被停止。它们可以被标记为停止状态,但实际上它们会在后台继续运行。

0
0 Comments

在使用Python的Requests库进行网络请求时,有时候需要限制下载响应的时间。下面是一个使用Requests库进行时间限制响应下载的解决方法。

当使用Requests库的prefetch=False参数时,可以一次拉取任意大小的响应数据块,而不是一次性拉取全部数据。为了实现时间限制的响应下载,我们需要告诉Requests库不要预加载整个响应,并且自己维护一个读取数据的时间计数器,同时一次读取小块的数据。可以使用r.raw.read(CHUNK_SIZE)方法来读取数据块。以下是一个示例代码:

import requests
import time
CHUNK_SIZE = 2**12  # Bytes
TIME_EXPIRE = time.time() + 5  # Seconds
r = requests.get('http://ipv4.download.thinkbroadband.com/1GB.zip', prefetch=False)
data = ''
buffer = r.raw.read(CHUNK_SIZE)
while buffer:
    data += buffer
    buffer = r.raw.read(CHUNK_SIZE)
    if TIME_EXPIRE < time.time():
        # 超过5秒后退出循环
        data += buffer
        break
r.raw.release_conn()
print "Read %s bytes out of %s expected." % (len(data), r.headers['content-length'])

需要注意的是,由于最后的r.raw.read(...)可能需要消耗任意数量的时间,所以有时候可能会超过给定的5秒时间限制。但至少不依赖于多线程或套接字超时。

然而,这种方法并不总是有效,因为不仅最后一次的r.raw.read(...)可能需要消耗任意数量的时间,即使是每次r.raw.read(...)都可能会消耗不同的时间。这经常导致无法在指定的下载时间内完成从任意URL下载的任务。

这种情况下,套接字超时似乎是唯一可行的方法。

0
0 Comments

问题的出现原因是使用requests模块进行下载时,会阻塞程序执行,无法设置超时时间。解决方法是使用非阻塞的网络I/O,比如使用eventlet模块。下面的代码演示了如何使用eventlet模块进行时间限制的响应下载。

import eventlet
from eventlet.green import urllib2
from eventlet.timeout import Timeout
url5 = 'http://ipv4.download.thinkbroadband.com/5MB.zip'
url10 = 'http://ipv4.download.thinkbroadband.com/10MB.zip'
urls = [url5, url5, url10, url10, url10, url5, url5]
def fetch(url):
    response = bytearray()
    with Timeout(60, False):
        response = urllib2.urlopen(url).read()
    return url, len(response)
pool = eventlet.GreenPool()
for url, length in pool.imap(fetch, urls):
    if (not length):
        print "%s: timeout!" % (url)
    else:
        print "%s: %s" % (url, length)

运行以上代码可以得到如下结果:

http://ipv4.download.thinkbroadband.com/5MB.zip: 5242880
http://ipv4.download.thinkbroadband.com/5MB.zip: 5242880
http://ipv4.download.thinkbroadband.com/10MB.zip: timeout!
http://ipv4.download.thinkbroadband.com/10MB.zip: timeout!
http://ipv4.download.thinkbroadband.com/10MB.zip: timeout!
http://ipv4.download.thinkbroadband.com/5MB.zip: 5242880
http://ipv4.download.thinkbroadband.com/5MB.zip: 5242880

使用这段代码时,当超时触发时会发生什么?这里没有使用线程,但操作仍然是并行执行的。当超时触发时,正在进行的非阻塞操作会被取消,但不会强制终止。Socket会被关闭。

还有一个提到的库是GRequests: Asynchronous Requests,可以使用它进行异步请求。

0