Вопрос-Ответ

How to download image using requests

Как загрузить изображение с помощью запросов

Я пытаюсь загрузить и сохранить изображение из Интернета, используя модуль python requests.

Вот (рабочий) код, который я использовал:

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

Вот новый (нерабочий) код, использующий 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)

Можете ли вы мне помочь, какой атрибут из ответа использовать fromrequests?

Переведено автоматически
Ответ 1

Вы можете либо использовать response.raw файловый объект, либо выполнить итерацию по ответу.

Использование response.raw файлоподобного объекта по умолчанию не будет декодировать сжатые ответы (с помощью GZIP или deflate). Вы все равно можете принудительно распаковать его, установив для decode_content атрибута значение True (requests устанавливает его в False значение для управления самим декодированием). Затем вы можете использовать shutil.copyfileobj(), чтобы Python передавал данные в файловый объект:

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)

Для повторения ответа используйте цикл; подобное повторение гарантирует, что данные будут распакованы на этом этапе:

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)

Данные будут считываться фрагментами по 128 байт; если вы считаете, что другой размер фрагмента работает лучше, используйте Response.iter_content() метод с пользовательским размером фрагмента:

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)

Обратите внимание, что вам нужно открыть конечный файл в двоичном режиме, чтобы убедиться, что python не попытается перевести для вас новые строки. Мы также настроили stream=True так, что requests сначала не загружается все изображение в память.

Ответ 2

Получите файлоподобный объект из запроса и скопируйте его в файл. Это также позволит избежать одновременного чтения всего объекта в память.

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
Ответ 3

Как насчет этого, быстрого решения?

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)
Ответ 4

У меня такая же потребность в загрузке изображений с помощью запросов. Сначала я попробовал ответ Мартинна Питерса, и он хорошо работает. Но когда я создал профиль для этой простой функции, я обнаружил, что она использует слишком много вызовов функций по сравнению с urllib и urllib2.

Затем я попробовал способ, рекомендованный автором модуля запросов:

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))

Это значительно сократило количество вызовов функций, тем самым ускорив работу моего приложения.
Вот код моего профилировщика и результат.

#!/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()')

Результат для testRequest:

343080 function calls (343068 primitive calls) in 2.580 seconds

И результат для testRequest2:

3129 function calls (3105 primitive calls) in 0.024 seconds
python python-requests