Как выполнить загрузку ответа с ограниченным временем с запросами python?
при загрузке большого файла с python, я хочу поставить ограничение по времени не только для процесса подключения, но и для загрузки.
Я пытаюсь использовать следующий код python:
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())
это не работает (загрузка не ограничена по времени), как правильно отмечено в документах:https://requests.readthedocs.org/en/latest/user/quickstart/#timeouts
Это было бы здорово, если бы это было возможно:
r.raw.read(timeout = 10)
в вопрос в том, как ограничить время загрузки?
3 ответов
и ответ: Не используйте запросы, так как он блокирует. Используйте неблокирующий сетевой ввод-вывод, например 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
при использовании запросов' prefetch=False
параметр, вы можете тянуть в произвольных размеров куски respone в то время (а не все сразу).
что вам нужно сделать, это сказать запросам не загружать весь запрос и сохранить свое собственное время, сколько вы потратили на чтение до сих пор, при этом получая небольшие куски за раз. Вы можете получить кусок, используя 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():
# Quit after 5 seconds.
data += buffer
break
r.raw.release_conn()
print "Read %s bytes out of %s expected." % (len(data), r.headers['content-length'])
обратите внимание, что это может иногда быть немного больше чем 5 секунд, отведенных в качестве финала r.raw.read(...)
может отставать произвольное количество времени. Но, по крайней мере, это не зависит от многопоточности или таймаутов сокетов.
запустите загрузку в потоке, который вы можете прервать, если не закончите вовремя.
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']