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