true requests from async and python download stream python-requests

from - ¿Cómo descargar archivos de gran tamaño en python con requests.py?



requests python (4)

Es mucho más fácil si usa Response.raw y 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

Esto transmite el archivo al disco sin utilizar una memoria excesiva, y el código es simple.

Requests es una biblioteca muy agradable. Me gustaría usarlo para descargar archivos grandes (> 1GB). El problema es que no es posible mantener todo el archivo en la memoria. Necesito leerlo en partes. Y este es un problema con el siguiente código.

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

Por alguna razón no funciona de esta manera. Todavía carga la respuesta en la memoria antes de guardarla en un archivo.

ACTUALIZAR

Si necesita un cliente pequeño (Python 2.x /3.x) que pueda descargar archivos grandes desde FTP, puede encontrarlo here . Admite subprocesos múltiples y reconecta (monitorea las conexiones) y también ajusta los parámetros de socket para la tarea de descarga.


Me di cuenta de lo que debería cambiarse. El truco fue establecer stream = True en el método get() .

Después de que este proceso de Python se detuvo para chupar la memoria (se mantiene alrededor de 30kb independientemente del tamaño del archivo de descarga).

Gracias @danodonovan por tu sintaxis, lo uso aquí:

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

Consulte http://docs.python-requests.org/en/latest/user/advanced/#body-content-workflow para obtener más información.


No es exactamente lo que estaba preguntando OP, pero ... es ridículamente fácil hacerlo con 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)

O de esta manera, si desea guardarlo en un archivo temporal:

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)

Observé el proceso:

watch ''ps -p 18647 -o pid,ppid,pmem,rsz,vsz,comm,args; ls -al *.iso''

Y vi crecer el archivo, pero el uso de memoria se mantuvo en 17 MB. ¿Me estoy perdiendo de algo?


Su tamaño de trozo podría ser demasiado grande, ¿ha intentado eliminar eso, tal vez 1024 bytes a la vez? (También, puedes usar with para ordenar la sintaxis)

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

Por cierto, ¿cómo deduce que la respuesta se ha cargado en la memoria?

Parece que Python no está vaciando los datos para archivar, de otras preguntas de SO , podría probar f.flush() y os.fsync() para forzar la escritura y la memoria libre del archivo;

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())