web-dev-qa-db-fra.com

Comment télécharger une image à l'aide de requêtes

J'essaie de télécharger et d'enregistrer une image à partir du Web à l'aide du module requests de Python.

Voici le code (de travail) que j'ai utilisé:

img = urllib2.urlopen(settings.STATICMAP_URL.format(**data))
with open(path, 'w') as f:
    f.write(img.read())

Voici le nouveau code (non fonctionnel) utilisant requests:

r = requests.get(settings.STATICMAP_URL.format(**data))
if r.status_code == 200:
    img = r.raw.read()
    with open(path, 'w') as f:
        f.write(img)

Pouvez-vous m'aider sur quel attribut de la réponse utiliser de requests?

322
shkschneider

Vous pouvez soit utiliser le response.raw objet fichier , soit effectuer une itération sur la réponse.

Utiliser l'objet de type fichier response.raw ne décodera pas par défaut les réponses compressées (avec GZIP ou deflate). Vous pouvez quand même le forcer à décompresser en définissant l'attribut decode_content sur True (requests le définit sur False pour contrôler le décodage lui-même). Vous pouvez ensuite utiliser shutil.copyfileobj() pour que Python diffuse les données dans un objet fichier:

import requests
import shutil

r = requests.get(settings.STATICMAP_URL.format(**data), stream=True)
if r.status_code == 200:
    with open(path, 'wb') as f:
        r.raw.decode_content = True
        shutil.copyfileobj(r.raw, f)        

Pour parcourir la réponse, utilisez une boucle; itérer ainsi permet de décompresser les données à cette étape:

r = requests.get(settings.STATICMAP_URL.format(**data), stream=True)
if r.status_code == 200:
    with open(path, 'wb') as f:
        for chunk in r:
            f.write(chunk)

Cela lira les données en morceaux de 128 octets; si vous pensez qu'une autre taille de bloc fonctionne mieux, utilisez la méthode Response.iter_content() avec une taille de bloc personnalisée:

r = requests.get(settings.STATICMAP_URL.format(**data), stream=True)
if r.status_code == 200:
    with open(path, 'wb') as f:
        for chunk in r.iter_content(1024):
            f.write(chunk)

Notez que vous devez ouvrir le fichier de destination en mode binaire pour vous assurer que python n'essaie pas de traduire les nouvelles lignes pour vous. Nous avons également paramétré stream=True pour que requests ne télécharge pas d'abord l'image complète dans la mémoire.

462
Martijn Pieters

Obtenez un objet de type requête à partir de la demande et copiez-le dans un fichier. Cela évitera également de lire le tout dans la mémoire en une fois.

import shutil

import requests

url = 'http://example.com/img.png'
response = requests.get(url, stream=True)
with open('img.png', 'wb') as out_file:
    shutil.copyfileobj(response.raw, out_file)
del response
199
Oleh Prypin

Que diriez-vous de cela, une solution rapide.

import requests

url = "http://craphound.com/images/1006884_2adf8fc7.jpg"
response = requests.get(url)
if response.status_code == 200:
    with open("/Users/Apple/Desktop/sample.jpg", 'wb') as f:
        f.write(response.content)
143
kiranbkrishna

J'ai le même besoin de télécharger des images à l'aide de requêtes. J'ai d'abord essayé la réponse de Martijn Pieters, et ça marche bien. Mais quand j'ai créé un profil sur cette fonction simple, j'ai constaté qu'il utilise autant d'appels de fonction que urllib et urllib2.

J'ai ensuite essayé le façon recommandée par l'auteur du module de requêtes:

import requests
from PIL import Image
# python2.x, use this instead  
# from StringIO import StringIO
# for python3.x,
from io import StringIO

r = requests.get('https://example.com/image.jpg')
i = Image.open(StringIO(r.content))

Ceci beaucoup plus réduit le nombre d'appels de fonction, accélérant ainsi mon application. Voici le code de mon profileur et le résultat.

#!/usr/bin/python
import requests
from StringIO import StringIO
from PIL import Image
import profile

def testRequest():
    image_name = 'test1.jpg'
    url = 'http://example.com/image.jpg'

    r = requests.get(url, stream=True)
    with open(image_name, 'wb') as f:
        for chunk in r.iter_content():
            f.write(chunk)

def testRequest2():
    image_name = 'test2.jpg'
    url = 'http://example.com/image.jpg'

    r = requests.get(url)

    i = Image.open(StringIO(r.content))
    i.save(image_name)

if __== '__main__':
    profile.run('testUrllib()')
    profile.run('testUrllib2()')
    profile.run('testRequest()')

Le résultat pour testRequest:

343080 function calls (343068 primitive calls) in 2.580 seconds

Et le résultat pour testRequest2:

3129 function calls (3105 primitive calls) in 0.024 seconds
69
Zhenyi Zhang

Cela pourrait être plus facile que d'utiliser requests. C’est la seule fois où je suggérerai de ne pas utiliser requests pour effectuer des opérations HTTP.

Deux doublures utilisant urllib:

>>> import urllib
>>> urllib.urlretrieve("http://www.example.com/songs/mp3.mp3", "mp3.mp3")

Il existe également un module Nice Python nommé wget assez facile à utiliser. Trouvé ici .

Cela démontre la simplicité du design:

>>> import wget
>>> url = 'http://www.futurecrew.com/skaven/song_files/mp3/razorback.mp3'
>>> filename = wget.download(url)
100% [................................................] 3841532 / 3841532>
>> filename
'razorback.mp3'

Prendre plaisir.

Edit: Vous pouvez également ajouter un paramètre out pour spécifier un chemin.

>>> out_filepath = <output_filepath>    
>>> filename = wget.download(url, out=out_filepath)
41
Blairg23

L'extrait de code suivant télécharge un fichier.

Le fichier est enregistré avec son nom de fichier comme dans l'URL spécifiée.

import requests

url = "http://beispiel.dort/ichbineinbild.jpg"
filename = url.split("/")[-1]
r = requests.get(url, timeout=0.5)

if r.status_code == 200:
    with open(filename, 'wb') as f:
        f.write(r.content)
24
Katja Süss

Il y a 2 manières principales:

  1. Utiliser .content (le plus simple/officiel) (voir réponse de Zhenyi Zhang ):

    import io  # Note: io.BytesIO is StringIO.StringIO on Python2.
    import requests
    
    r = requests.get('http://lorempixel.com/400/200')
    r.raise_for_status()
    with io.BytesIO(r.content) as f:
        with Image.open(f) as img:
            img.show()
    
  2. Utiliser .raw (voir réponse de Martijn Pieters ):

    import requests
    
    r = requests.get('http://lorempixel.com/400/200', stream=True)
    r.raise_for_status()
    r.raw.decode_content = True  # Required to decompress gzip/deflate compressed responses.
    with PIL.Image.open(r.raw) as img:
        img.show()
    r.close()  # Safety when stream=True ensure the connection is released.
    

Le timing des deux ne montre aucune différence notable.

13
Wernight

Aussi facile que d'importer des images et des requêtes

from PIL import Image
import requests

img = Image.open(requests.get(url, stream = True).raw)
img.save('img1.jpg')
9
Riccardo D

Voici une réponse plus conviviale qui utilise toujours le streaming.

Il suffit de définir ces fonctions et d’appeler getImage(). Il utilisera le même nom de fichier que l'URL et écrira par défaut dans le répertoire actuel, mais les deux peuvent être modifiés.

import requests
from StringIO import StringIO
from PIL import Image

def createFilename(url, name, folder):
    dotSplit = url.split('.')
    if name == None:
        # use the same as the url
        slashSplit = dotSplit[-2].split('/')
        name = slashSplit[-1]
    ext = dotSplit[-1]
    file = '{}{}.{}'.format(folder, name, ext)
    return file

def getImage(url, name=None, folder='./'):
    file = createFilename(url, name, folder)
    with open(file, 'wb') as f:
        r = requests.get(url, stream=True)
        for block in r.iter_content(1024):
            if not block:
                break
            f.write(block)

def getImageFast(url, name=None, folder='./'):
    file = createFilename(url, name, folder)
    r = requests.get(url)
    i = Image.open(StringIO(r.content))
    i.save(file)

if __== '__main__':
    # Uses Less Memory
    getImage('http://www.example.com/image.jpg')
    # Faster
    getImageFast('http://www.example.com/image.jpg')

Les request entrailles de getImage() sont basées sur la réponse ici et les entrailles de getImageFast() sont basées sur la réponse ci-dessus .

4
Chris Redford

lorsque j'essaie d'exécuter le code ci-dessous, l'image est en cours de téléchargement mais la taille est toujours limitée à 34 Ko.

import requests
import shutil

r = requests.get(settings.STATICMAP_URL.format(**data), stream=True)
if r.status_code == 200:
with open(path, 'wb') as f:
    r.raw.decode_content = True
    shutil.copyfileobj(r.raw, f)  

Et aussi s'il vous plaît laissez-moi savoir ce qui est settings.STATICMAP_URL.format (** data), j'utilise mon usl au lieu de settings.STATICMAP_URL.format (** data)

2
Logic lover

Je vais poster une réponse car je n'ai pas assez de représentants pour faire un commentaire, mais avec wget tel que posté par Blairg23, vous pouvez également fournir un paramètre de sortie pour le chemin.

 wget.download(url, out=path)
2
justincc

Ceci est la première réponse qui se présente pour les recherches Google sur la façon de télécharger un fichier binaire avec des demandes. Si vous avez besoin de télécharger un fichier arbitraire avec des requêtes, vous pouvez utiliser:

import requests
url = 'https://s3.amazonaws.com/lab-data-collections/GoogleNews-vectors-negative300.bin.gz'
open('GoogleNews-vectors-negative300.bin.gz', 'wb').write(requests.get(url, allow_redirects=True).content)
1
duhaime