Comment télécharger un gros fichier en python avec requests.py Je ne sais pas.

Demandes est une très belle bibliothèque. J'aimerais l'utiliser pour télécharger de gros fichiers (>1 GO). Le problème est qu'il n'est pas possible de garder tout le fichier en mémoire.j'ai besoin de le lire en morceaux. Et c'est un problème avec le code suivant

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 

pour une raison quelconque, ça ne marche pas comme ça. Il charge encore la réponse en mémoire avant de la sauvegarder dans un fichier.

mise à JOUR

si vous avez besoin d'un petit client (Python 2.x / 3.x) qui peut télécharger de gros fichiers à partir de FTP, vous pouvez le trouver ici . Il prend en charge multithreading & reconnects (il surveille les connexions) il tunes socket params aussi pour la tâche de téléchargement.

254
demandé sur Roman Podlinov 2013-05-22 18:47:37

4 réponses

j'ai trouvé ce qui devait être changé. Le truc était de mettre stream = True dans la méthode get() .

après ce processus python s'est arrêté pour sucer la mémoire (reste autour de 30kb quelle que soit la taille du fichier de téléchargement).

Merci @danodonovan pour votre syntaxe Je l'utilise ici:

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

voir http://docs.python-requests.org/en/latest/user/advanced/#body-content-workflow pour plus référence.

469
répondu Roman Podlinov 2015-12-30 13:32:43

c'est beaucoup plus facile si vous utilisez Response.raw et 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

cela renvoie le fichier vers le disque sans utiliser de mémoire excessive, et le code est simple.

117
répondu John Zwinck 2016-08-30 02:13:18

votre taille de morceau pourrait être trop grand, avez - vous essayé de laisser tomber que-peut-être 1024 octets à la fois? (aussi, vous pouvez utiliser with pour nettoyer la syntaxe)

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 

D'ailleurs, comment déduisez-vous que la réponse a été chargée dans la mémoire?

cela sonne comme si python n'était pas en train de débusquer les données vers le fichier, à partir d'autres donc questions vous pourriez essayer f.flush() et os.fsync() pour forcer le fichier à écrire et mémoire libre;

    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())
36
répondu danodonovan 2017-05-23 10:31:30

pas exactement ce que L'OP demandait, mais... c'est ridiculement facile de faire ça avec 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)

Ou de cette façon, si vous voulez l'enregistrer dans un fichier temporaire:

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)

j'ai regardé le processus:

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

et j'ai vu le fichier grandir, mais l'utilisation de la mémoire est restée à 17 Mo. Ai-je raté quelque chose?

26
répondu x-yuri 2017-06-15 09:14:18