web-dev-qa-db-fra.com

Quelle est la meilleure façon de télécharger un fichier en utilisant urllib3

Je souhaite télécharger un fichier via le protocole HTTP à l'aide de urllib3. J'ai réussi à le faire en utilisant le code suivant:

 url = 'http://url_to_a_file'
 connection_pool = urllib3.PoolManager()
 resp = connection_pool.request('GET',url )
 f = open(filename, 'wb')
 f.write(resp.data)
 f.close()
 resp.release_conn()

Mais je me demandais quelle était la façon appropriée de faire cela. Par exemple, cela fonctionnera-t-il bien pour les gros fichiers et si ce n'est pas quoi faire pour rendre ce code plus tolérant aux bogues et évolutif.

Remarque. Il est important pour moi d'utiliser urllib3 bibliothèque pas urllib2 par exemple, car je veux que mon code soit thread-safe.

16
running.t

Votre extrait de code est proche. Deux choses à noter:

  1. Si vous utilisez resp.data, Il consommera l'intégralité de la réponse et renverra la connexion (vous n'avez pas besoin de resp.release_conn() manuellement). C'est très bien si vous êtes cool avec la conservation des données en mémoire.

  2. Vous pouvez utiliser resp.read(amt) qui diffusera la réponse, mais la connexion devra être retournée via resp.release_conn().

Cela ressemblerait à quelque chose comme ...

import urllib3
http = urllib3.PoolManager()
r = http.request('GET', url, preload_content=False)

with open(path, 'wb') as out:
    while True:
        data = r.read(chunk_size)
        if not data:
            break
        out.write(data)

r.release_conn()

La documentation peut manquer un peu sur ce scénario. Si quelqu'un est intéressé à faire une pull-request pour améliorer la documentation urllib , cela serait grandement apprécié. :)

24
shazow

La façon la plus correcte de le faire est probablement d'obtenir un objet de type fichier qui représente la réponse HTTP et de le copier dans un fichier réel en utilisant shutil.copyfileobj comme ci-dessous:

url = 'http://url_to_a_file'
c = urllib3.PoolManager()

with c.request('GET',url, preload_content=False) as resp, open(filename, 'wb') as out_file:
    shutil.copyfileobj(resp, out_file)

resp.release_conn()     # not 100% sure this is required though
5
Alecz