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
?
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.
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
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)
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
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)
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)
Il y a 2 manières principales:
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()
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.
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')
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 .
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)
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)
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)