요청을 사용하여 이미지를 다운로드하는 방법


367

파이썬 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)

응답에서 어떤 속성을 사용할 수 있는지 알려 주 requests시겠습니까?


15
사용하려면 = 설정 스트림에 진정한 필요 r.raw
clsung

이것이 귀하의 질문에 대답합니까? 요청과 함께 파이썬으로 큰 파일 다운로드
AMC

답변:


516

response.raw파일 객체 를 사용하거나 응답을 반복 할 수 있습니다 .

response.raw파일과 같은 객체 를 사용하는 것은 기본적으로 압축 된 응답 (GZIP 또는 deflate)을 디코딩하지 않습니다. decode_content어트리뷰트를 True(로 requests설정하여 False디코딩 자체를 제어 하도록 설정하여) 어쨌든 압축을 풀도록 할 수 있습니다 . 그런 다음 shutil.copyfileobj()파이썬이 데이터를 파일 객체로 스트리밍 하도록 할 수 있습니다 :

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)

파이썬이 줄 바꿈을 시도하고 변환하지 않도록 대상 파일을 이진 모드로 열어야합니다. 우리는 또한 설정 stream=True이 그래서 requests먼저 메모리에 전체 이미지를 다운로드하지 않습니다.


2
귀하의 답변을 통해 텍스트 파일에서 데이터를 찾을 수 있었으며 사용한 단계는 r2 = requests.post(r.url, data); print r2.content입니다. 그러나 이제 나는 또한 알고 싶다 filename. 그들의 청소 방법은 무엇입니까? -현재 헤더에서 파일 이름을 찾았 r2.headers['content-disposition'] 습니다. 출력을 다음과 같이 제공합니다. 파일 이름 'attachment; filename=DELS36532G290115.csi' 으로이 문자열을 구문 분석하고 있습니다 ... 더 확실한 방법입니까?
Grijesh Chauhan

6
@GrijeshChauhan : 예, content-disposition헤더는 여기가는 길입니다. 사용하는 cgi.parse_header()매개 변수를 구문 분석하고 얻을; params = cgi.parse_header(r2.headers['content-disposition'])[1]그때 params['filename'].
Martijn Pieters

1
기본 128 바이트 청크를 얻으려면, 당신은 할 필요가 오버 반복 requests.Response자체를 : for chunk in r: .... iter_content()없이 호출 chunk_size하면 1 바이트 단위로 반복됩니다 .
dtk

@ dtk : 감사합니다. 답을 업데이트하겠습니다. 답변을 게시 한 후 반복이 변경되었습니다 .
Martijn Pieters

1
@KumZ의 두 가지 이유 : response.ok문서화 된 적이 없으며 1xx, 2xx 또는 3xx 상태에 해당하지만 200 응답 만 응답 본문이 있습니다.
Martijn Pieters

232

요청에서 파일과 같은 객체를 가져 와서 파일로 복사합니다. 이것은 또한 모든 것을 한 번에 메모리로 읽는 것을 피할 것입니다.

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

14
돌아와서 답변 해 주셔서 감사합니다. 다른 답변은 효과가 있지만, 이것은 더
뛰어나고

11
이미지에는 이미 자체 압축이 있으므로 이미지를 GZIP로 설정 한 서버가 거의 없다는 점에 주목할 가치가 있습니다. 그것은 비생산적이며 거의 이익없이 CPU 사이클을 낭비합니다. 따라서 이것은 텍스트 콘텐츠, 특히 이미지에서는 문제가 될 수 있습니다.
phette23

3
우리가 원래 파일명에 접근 할 수있는 방법이
있습니까

@ phette23 또한 Google PageSpeed가보고하고 기본적으로 수행한다는 점에 주목할 가치가 있습니다.
Wernight

8
때문에 설정 r.raw.decode_content = True해야 shutil.copyfileobj(response.raw, out_file)하므로 by default, decode compressed responses (with GZIP or deflate)파일이 0 인 이미지가 표시됩니다.
Simin Jie

166

빠른 해결책 인 이건 어떻습니까?

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)

1
당신은 무엇을 의미합니까! f = open("/Users/apple/Desktop/sample.jpg", 'wb')이 길에서 무엇을 의미합니까!? 이미지를 다운로드하고 싶습니다
미소

3
이미지 파일을 쓸 수있는 지정된 경로에 파일 설명자가 열립니다.
kiranbkrishna

@AndrewGlazkov 사용하는 것이 더 파이썬적인 것 같아요if response.ok:
EndermanAPM

5
response.ok는 1xx, 2xx 또는 3xx 상태에 대해 True이지만 위의 주석에서 언급 된 @Martijn Pieters와 같은 응답 본문은 200 개입니다.
annndrey

75

요청을 사용하여 이미지를 다운로드해야 할 필요가 동일합니다. 나는 먼저 Martijn Pieters의 답변을 시도했지만 잘 작동합니다. 그러나이 간단한 함수에 대한 프로파일을 만들 때 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

12
chunk_size기본적으로 1로 설정된 매개 변수를 지정하지 않았 으므로 iter_content결과 스트림을 한 번에 1 바이트 씩 반복하기 때문입니다. python-requests.org/en/latest/api/… 문서를 참조하십시오 .
CadentOrange

9
또한 전체 응답을 메모리에로드하므로 피할 수 있습니다. PIL여기서도 사용할 수 없으며 with open(image_name, 'wb') as outfile: outfile.write(r.content)충분합니다.
Martijn Pieters

3
PIL또한 표준 라이브러리에 없으므로 이식성이 떨어집니다.
jjj

2
@ZhenyiZhang iter_contentchunk_size너무 작기 때문에 속도가 느립니다. 100k로 늘리면 훨씬 빠릅니다.

이것이 가장 좋은 대답입니다. 파일을 메모리로 읽는 것이 항상 최선 인 것은 아니지만 OP가 지정한 "이미지"는 파일이 일반적으로 4MB보다 작으므로 메모리에 미미한 영향을 미칩니다.
Chris Conlan

51

사용하는 것보다 쉽습니다 requests. 이것은 requestsHTTP 작업을 사용 하지 않는 것이 좋습니다 .

사용하는 두 개의 라이너 urllib:

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

wget꽤 사용하기 쉬운 멋진 파이썬 모듈도 있습니다. 찾을 여기 .

이것은 디자인의 단순성을 보여줍니다.

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

즐겨.

편집 :out 매개 변수를 추가하여 경로를 지정할 수도 있습니다 .

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

wget번거 로움없이 사용했습니다 . 다음을 사용하여 얻을 수있는 이점을 urllib3
알려

1
이 답변은 Python 2에 대한 것입니다. Python 3의 경우 수행해야합니다 urllib.request.urlretrieve("http://example.com", "file.ext").
허스키

1
감사합니다 @Husky. 업데이트되었습니다.
Blairg23

28

다음 코드 스 니펫은 파일을 다운로드합니다.

파일은 지정된 URL과 같이 파일 이름으로 저장됩니다.

import requests

url = "http://example.com/image.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)

16

두 가지 주요 방법이 있습니다.

  1. .content(가장 단순한 / 공식적인) 사용 ( 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. 사용 .raw( 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.

두 타이밍 모두 눈에 띄는 차이가 없습니다.


2
나는 많은 답변을 시도했으며, 귀하의 1.답변 ( io.BytesIO및 사용 Image)은 Python 3.6에서 나를 위해 일한 첫 번째 답변 이었습니다. 잊지 마세요 from PIL import Image(과 pip install Pillow).
colllin

.content와 .raw의 차이점은 무엇입니까?
foxiris

13

이미지 및 요청을 가져 오는 것만 큼 쉬움

from PIL import Image
import requests

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

4

여전히 스트리밍을 사용하는보다 사용자 친화적 인 답변입니다.

이 함수를 정의하고를 호출하십시오 getImage(). URL과 동일한 파일 이름을 사용하고 기본적으로 현재 디렉토리에 쓰지만 둘 다 변경할 수 있습니다.

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

request의 내장 getImage()대답을 기반으로 여기에 와의 용기는 getImageFast()그 대답을 기반으로 .


3

의견을 작성하기에 충분한 담당자가 없으므로 답변을 게시하려고하지만 Blairg23이 게시 한 wget을 사용하면 경로에 대한 매개 변수를 제공 할 수도 있습니다.

 wget.download(url, out=path)

2

요청이 포함 된 이진 파일을 다운로드하는 방법에 대한 Google 검색에서 나타나는 첫 번째 응답입니다. 요청이있는 임의의 파일을 다운로드해야하는 경우 다음을 사용할 수 있습니다.

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
좋은! 심지어 암시 적 .close()이다. 이것은 2019 년 현재 가장 좋은 대답입니다.
Daniel W.

2

이것이 내가 한 방법입니다

import requests
from PIL import Image
from io import BytesIO

url = 'your_url'
files = {'file': ("C:/Users/shadow/Downloads/black.jpeg", open('C:/Users/shadow/Downloads/black.jpeg', 'rb'),'image/jpg')}
response = requests.post(url, files=files)

img = Image.open(BytesIO(response.content))
img.show()

-1

다음과 같이 할 수 있습니다 :

import requests
import random

url = "https://images.pexels.com/photos/1308881/pexels-photo-1308881.jpeg? auto=compress&cs=tinysrgb&dpr=1&w=500"
name=random.randrange(1,1000)
filename=str(name)+".jpg"
response = requests.get(url)
if response.status_code.ok:
   with open(filename,'w') as f:
    f.write(response.content)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.