Cómo descargar imágenes usando solicitudes


Estoy intentando descargar y guardar una imagen de la web usando el módulo requests de python.

Aquí está el código (de trabajo) que usé:

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

Aquí está el nuevo código (que no funciona) usando 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)

¿Puedes ayudarme en qué atributo de la respuesta usar de requests?

Author: shkschneider, 2012-10-30

11 answers

Puede utilizar el response.raw file object , o iterar sobre la respuesta.

Usar el objeto similar a un archivo response.raw no decodificará, por defecto, las respuestas comprimidas (con GZIP o deflate). Puede forzar que se descomprima por usted de todos modos estableciendo el atributo decode_content a True (requests lo establece en False para controlar la decodificación por sí mismo). A continuación, puede utilizar shutil.copyfileobj() para que Python transmita los datos a un objeto file:

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)        

Para iterar sobre la respuesta use un bucle; iterar de esta manera asegura que los datos se descompriman en esta etapa:

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)

Esto leerá los datos en fragmentos de 128 bytes; si siente que otro tamaño de fragmento funciona mejor, use el Response.iter_content() método con un tamaño de fragmento personalizado:

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)

Tenga en cuenta que debe abrir el archivo de destino en modo binario para asegurarse de que python no intente traducir nuevas líneas por usted. También configuramos stream=True para que requests no descargue la imagen completa en memoria primero.

 401
Author: Martijn Pieters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-25 10:38:34

Obtenga un objeto similar a un archivo de la solicitud y cópielo en un archivo. Esto también evitará leer todo en la memoria a la vez.

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
 171
Author: Oleh Prypin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-13 21:24:48

Qué tal esto, una solución rápida.

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)
 102
Author: kiranbkrishna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-11 01:25:41

Tengo la misma necesidad de descargar imágenes usando peticiones. Primero probé la respuesta de Martijn Pieters, y funciona bien. Pero cuando hice un perfil en esta función simple, encontré que utiliza tantas llamadas de función en comparación con urllib y urllib2.

Luego probé la forma recomendada por el autor del módulo de solicitudes:

import requests
from PIL import Image
from StringIO import StringIO

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

Esto redujo mucho más el número de llamadas a funciones, por lo tanto aceleró mi aplicación. Aquí está el código de mi perfilador y el resultado.

#!/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 __name__ == '__main__':
    profile.run('testUrllib()')
    profile.run('testUrllib2()')
    profile.run('testRequest()')

El resultado de testRequest:

343080 function calls (343068 primitive calls) in 2.580 seconds

Y el resultado de testRequest2:

3129 function calls (3105 primitive calls) in 0.024 seconds
 56
Author: Zhenyi Zhang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-07 15:52:16

Esto podría ser más fácil que usar requests. Esta es la única vez que sugeriré no usar requests para hacer cosas HTTP.

Dos líneas usando urllib:

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

También hay un bonito módulo de Python llamado wget que es bastante fácil de usar. Se encuentra aquí.

Esto demuestra la simplicidad del diseño:

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

Disfruta.

Edit: También puede agregar un parámetro out para especificar una ruta de acceso.

>>> out_filepath = <output_filepath>    
>>> filename = wget.download(url, out=out_filepath)
 34
Author: Blairg23,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-15 05:41:36

El siguiente fragmento de código descarga un archivo.

El archivo se guarda con su nombre de archivo como en la url especificada.

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)
 17
Author: Katja Süss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-07 19:42:01

Hay 2 maneras principales:

  1. Usando .content (más simple / oficial) (ver Respuesta 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. Usando .raw (ver Respuesta 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.
    

La sincronización de ambos no muestra una diferencia notable.

 10
Author: Wernight,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:26

Aquí hay una respuesta más fácil de usar que todavía usa streaming.

Simplemente defina estas funciones y llame a getImage(). Utilizará el mismo nombre de archivo que la url y escribirá en el directorio actual de forma predeterminada, pero ambos se pueden cambiar.

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 __name__ == '__main__':
    # Uses Less Memory
    getImage('http://www.example.com/image.jpg')
    # Faster
    getImageFast('http://www.example.com/image.jpg')

El request entrañas de getImage() se basan en la respuesta aquí y el valor de getImageFast() se basan en la respuesta arriba.

 3
Author: Chris Redford,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:47

Voy a publicar una respuesta ya que no tengo suficiente rep para hacer un comentario, pero con wget como publicado por Blairg23, también puede proporcionar un parámetro de salida para la ruta.

 wget.download(url, out=path)
 2
Author: justincc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-24 13:50:40

Cuando intento ejecutar el siguiente código,la imagen se está degradando, pero el tamaño siempre se limita a 34 KB.

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)  

Y también, por favor, háganme saber qué es la configuración.STATICMAP_URL.formato (**datos), estoy usando mi usl en lugar de la configuración.STATICMAP_URL.formato (**datos)

 2
Author: Logic lover,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-03 05:40:07

Tan fácil como importar imágenes y solicitudes

from PIL import Image
import requests

img = Image.open(requests.get(url, stream = True).raw)
img.save('img1.jpg')
 1
Author: Riccardo D,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-17 08:33:37