Как скачать большой файл на python с помощью requests.py?
запросы - это действительно хорошая библиотека. Я хотел бы использовать его для загрузки больших файлов (>1ГБ).
Проблема в том, что невозможно сохранить весь файл в памяти, мне нужно прочитать его кусками. И это проблема со следующим кодом
import requests
def DownloadFile(url)
local_filename = url.split('/')[-1]
r = requests.get(url)
f = open(local_filename, 'wb')
for chunk in r.iter_content(chunk_size=512 * 1024):
if chunk: # filter out keep-alive new chunks
f.write(chunk)
f.close()
return
по какой-то причине это не работает таким образом. Он по-прежнему загружает ответ в память, прежде чем сохранить его в файл.
обновление
Если вам нужен небольшой клиент (Python 2.x / 3.x) который может скачать большие файлы с FTP, вы можете найти его здесь. Он поддерживает многопоточность и переподключается (он контролирует соединения), а также настраивает параметры сокета для задачи загрузки.
4 ответов:
я понял, что надо менять. Хитрость заключалась в том, чтобы установить
stream = Trueнаget()метод.после этого процесс python перестал сосать память (остается около 30 КБ независимо от размера файла загрузки).
спасибо @danodonovan для вас синтаксис я использую его здесь:
def download_file(url): local_filename = url.split('/')[-1] # NOTE the stream=True parameter r = requests.get(url, stream=True) with open(local_filename, 'wb') as f: for chunk in r.iter_content(chunk_size=1024): if chunk: # filter out keep-alive new chunks f.write(chunk) #f.flush() commented by recommendation from J.F.Sebastian return local_filenameсм.http://docs.python-requests.org/en/latest/user/advanced/#body-content-workflow для дальнейшей справки.
Это гораздо проще, если вы используете
Response.rawиshutil.copyfileobj():import requests import shutil def download_file(url): local_filename = url.split('/')[-1] r = requests.get(url, stream=True) with open(local_filename, 'wb') as f: shutil.copyfileobj(r.raw, f) return local_filenameэто потоки файл на диск без использования избыточной памяти, и код прост.
ваш размер куска может быть слишком большим, вы пробовали отбросить это - может быть, 1024 байта за раз? (кроме того, вы можете использовать
withчтобы привести в порядок синтаксис)def DownloadFile(url): local_filename = url.split('/')[-1] r = requests.get(url) with open(local_filename, 'wb') as f: for chunk in r.iter_content(chunk_size=1024): if chunk: # filter out keep-alive new chunks f.write(chunk) returnкстати, как вы выводите, что ответ был загружен в память?
это звучит так, как будто python не сбрасывает данные в файл, из других поэтому вопросы вы могли бы попробовать
f.flush()иos.fsync()для принудительной записи файла и освобождения памяти;with open(local_filename, 'wb') as f: for chunk in r.iter_content(chunk_size=1024): if chunk: # filter out keep-alive new chunks f.write(chunk) f.flush() os.fsync(f.fileno())
не совсем то, что ОП спрашивал, но... это до смешного легко сделать с
urllib:from urllib.request import urlretrieve url = 'http://mirror.pnl.gov/releases/16.04.2/ubuntu-16.04.2-desktop-amd64.iso' dst = 'ubuntu-16.04.2-desktop-amd64.iso' urlretrieve(url, dst)или таким образом, если вы хотите сохранить его во временный файл:
from urllib.request import urlopen from shutil import copyfileobj from tempfile import NamedTemporaryFile url = 'http://mirror.pnl.gov/releases/16.04.2/ubuntu-16.04.2-desktop-amd64.iso' with urlopen(url) as fsrc, NamedTemporaryFile(delete=False) as fdst: copyfileobj(fsrc, fdst)Я наблюдал за процессом:
watch 'ps -p 18647 -o pid,ppid,pmem,rsz,vsz,comm,args; ls -al *.iso'и я видел, что файл растет, но использование памяти осталось на уровне 17 Мб. Я что-то упустил?
Comments