web-dev-qa-db-ja.com

リクエストを使用して画像をダウンロードする方法

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

requestsから使用するレスポンスのどの属性を手助けできますか?

304
shkschneider

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があなたのために改行を試みて翻訳しないことを確実にするためにあなたはバイナリモードで目的のファイルを開く必要があることに注意してください。また、requestsが画像全体を最初にメモリにダウンロードしないようにstream=Trueを設定します。

445
Martijn Pieters

リクエストからファイルのようなオブジェクトを取得し、それをファイルにコピーします。これにより、一度に全部をメモリに読み込むことも避けられます。

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
194
Oleh Prypin

これはどうでしょう、素早い解決策です。

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

リクエストを使用して画像をダウンロードする必要性も同じです。私は最初にMartijn Pietersの答えを試しました、そしてそれはうまくいきます。しかし、この単純な関数についてプロファイルを作成したところ、urllibとurllib2に比べて非常に多くの関数呼び出しを使用していることがわかりました。

私はそれから 推奨された方法 リクエストモジュールの作者によるものを試してみました:

import requests
from PIL import Image
from StringIO 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 __== '__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
68
Zhenyi Zhang

これはrequestsを使うより簡単かもしれません。これは私が今までにHTTPのことをするためにrequestsを使わないことを提案する唯一の時です。

urllibを使った2つのライナー:

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

とても使いやすいwgetという名前のNice Pythonモジュールもあります。見つかった ここ .

これはデザインの単純さを示しています。

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

次のコードスニペットはファイルをダウンロードします。

ファイルは指定されたURLのようにファイル名で保存されます。

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)
20
Katja Süss

主な方法は2つあります。

  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.
    

両方のタイミングで顕著な違いは見られません。

13
Wernight

画像やリクエストをインポートするのと同じくらい簡単

from PIL import Image
import requests

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

これはまだストリーミングを使用している、よりユーザーフレンドリーな答えです。

これらの関数を定義して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 __== '__main__':
    # Uses Less Memory
    getImage('http://www.example.com/image.jpg')
    # Faster
    getImageFast('http://www.example.com/image.jpg')

getImage()requestの内臓はanswer here に基づいており、getImageFast()の内臓はanswer above に基づいています。

4
Chris Redford

私が以下のコードを実行しようとすると、画像はdownalodeされていますが、サイズは常に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)  

また、settings.STATICMAP_URL.format(** data)とは何か教えてください。settings.STATICMAP_URL.format(** data)の代わりに自分のuslを使用しています。

2
Logic lover

私はコメントをするのに十分な担当者がいないので答えを投稿するつもりですが、Blairg23によって投稿されたようにwgetを使うと、あなたはまたパスのためにoutパラメータを提供することができます。

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

これは、リクエストを含むバイナリファイルをダウンロードする方法に関する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
duhaime