如何使用请求下载图像

shk*_*der 336 python urllib2 python-requests

我正在尝试使用python的requests模块从Web下载并保存图像.

这是我使用的(工作)代码:

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

以下是使用以下内容的新(非工作)代码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)
Run Code Online (Sandbox Code Playgroud)

你能帮助我从响应中使用什么属性requests吗?

Mar*_*ers 478

您可以使用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)        
Run Code Online (Sandbox Code Playgroud)

要迭代响应,请使用循环; 这样迭代可确保数据在此阶段解压缩:

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)
Run Code Online (Sandbox Code Playgroud)

这将以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)
Run Code Online (Sandbox Code Playgroud)

请注意,您需要以二进制模式打开目标文件,以确保python不会尝试为您翻译换行符.我们还设置stream=Truerequests不首先将整个图像下载到内存中.

  • @GrijeshChauhan:是的,`content-disposition`标题是去这里的方式; 使用[`cgi.parse_header()`](https://docs.python.org/2/library/cgi.html#cgi.parse_header)来解析它并获取参数; `params = cgi.parse_header(r2.headers ['content-disposition'])[1]```params ['filename']`. (5认同)
  • 在你的回答的帮助下,我能够在文本文件中找到数据,我使用的步骤是`r2 = requests.post(r.url,data); print r2.content`.但现在我也想知道`filename`.他们的清洁方式是什么? - 目前我在标题中找到了文件名 - "r2.headers ['content-disposition']`,它输出为:`'attachment; filename = DELS36532G290115.csi'`我正在解析这个字符串的文件名...是他们更清洁的方式吗? (2认同)
  • @KumZ 有两个原因:从未记录过 `response.ok`,它对任何 1xx、2xx 或 3xx 状态产生 true,但只有 200 响应具有响应正文。 (2认同)

Ole*_*pin 204

从请求中获取类似文件的对象并将其复制到文件中.这也将避免一次将整个内容读入内存.

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
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢您回来并回答这个问题.虽然另一个答案是有效的,但这个问题的突飞猛进 (14认同)
  • 值得注意的是,很少有服务器设置为GZIP他们的图像,因为图像已经有自己的压缩.这会适得其反,浪费CPU周期,几乎没有任何好处.因此,虽然这可能是文本内容的问题,特别是图像不是. (11认同)
  • 应该在`shutil.copyfileobj(response.raw,out_file)之前设置`r.raw.decode_content = True`,因为`默认情况下,解码压缩的响应(使用GZIP或deflate)`,这样你就会得到零文件图像. (7认同)
  • 有什么办法可以访问原始文件名 (2认同)

kir*_*hna 148

怎么样,一个快速的解决方案.

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)
Run Code Online (Sandbox Code Playgroud)

  • 这将在指定的路径中打开文件描述符,以便可以写入映像文件. (3认同)
  • 对于任何1xx,2xx或3xx状态,response.ok为True,但只有200个响应具有响应主体,如上面评论中提到的@Martijn Pieters (3认同)

Zhe*_*ang 71

我同样需要使用请求下载图像.我首先尝试了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))
Run Code Online (Sandbox Code Playgroud)

这大大减少了函数调用的数量,从而加快了我的应用程序.这是我的探查器的代码和结果.

#!/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()')
Run Code Online (Sandbox Code Playgroud)

testRequest的结果:

343080 function calls (343068 primitive calls) in 2.580 seconds
Run Code Online (Sandbox Code Playgroud)

而testRequest2的结果:

3129 function calls (3105 primitive calls) in 0.024 seconds
Run Code Online (Sandbox Code Playgroud)

  • 这是因为你没有指定`chunk_size`参数,默认为1,所以`iter_content`一次迭代结果流1个字节.请参阅文档http://www.python-requests.org/en/latest/api/#requests.Response.iter_content. (12认同)
  • 这也会将整个响应加载到内存中,您可能希望避免这种情况.这里也没有使用`PIL`,只有`open(image_name,'wb')作为outfile:outfile.write(r.content)`就足够了. (9认同)
  • 根据请求作者“http://docs.python-requests.org/en/latest/user/quickstart/#binary-response-content”,“from StringIO import StringIO”现在似乎是“from io import BytesIO” ` (8认同)
  • `PIL`也不在标准库中,这使得它的便携性降低. (3认同)
  • @ZhenyiZhang`iter_content`很慢,因为你的`chunk_size`太小了,如果把它增加到100k就会快得多. (2认同)

Bla*_*g23 41

这可能比使用更容易requests.这是我唯一一次建议不要requests用来做HTTP的东西.

两个班轮使用urllib:

>>> import urllib
>>> urllib.urlretrieve("http://www.example.com/songs/mp3.mp3", "mp3.mp3")
Run Code Online (Sandbox Code Playgroud)

还有一个很好的Python模块wget,它很容易使用.在这里找到.

这表明了设计的简洁性:

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

请享用.

编辑:您还可以添加out参数以指定路径.

>>> out_filepath = <output_filepath>    
>>> filename = wget.download(url, out=out_filepath)
Run Code Online (Sandbox Code Playgroud)

  • 请注意,此答案适用于 Python 2。对于 Python 3,您需要执行 `urllib.request.urlretrieve("http://example.com", "file.ext")`。 (2认同)

小智 26

以下代码段下载文件.

文件的文件名保存在指定的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)
Run Code Online (Sandbox Code Playgroud)


Wer*_*ght 14

主要有两种方式:

  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()
    
    Run Code Online (Sandbox Code Playgroud)
  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.
    
    Run Code Online (Sandbox Code Playgroud)

时间两者都没有显示出明显的差异.

  • 我尝试了一堆答案,你的`1.`答案(使用`io.BytesIO`和`Image`)是第一个在Python 3.6上为我工作的答案.不要忘记`来自PIL import Image`(和'pip install Pillow`). (2认同)

Ric*_*o D 12

像导入图像和请求一样简单

from PIL import Image
import requests

img = Image.open(requests.get(url, stream = True).raw)
img.save('img1.jpg')
Run Code Online (Sandbox Code Playgroud)


alv*_*vas 7

长话短说

总结其他人的精彩答案。

方法 需求requests 需要PIL 需要...
requests.get->shutil 是的 -
requests.get->open(mode="wb") 是的 -
requests.get-> ByteIO->Image.save 是的 是的 -
urllib - - -
wget wget
requests.get-> PIL.Image->np.save 是的 是的 numpy

使用shutil并输出解码后的原始内容requests.get

原始答案修改自/sf/answers/919651141/

import shutil
import requests

img_url = 'https://techcrunch.com/wp-content/uploads/2023/03/dpreview.jpg'

response = requests.get(img_url, stream=True)        
with open('dpreview.jpg', 'wb') as fout:
    response.raw.decode_content = True
    shutil.copyfileobj(response.raw, fout)             

Run Code Online (Sandbox Code Playgroud)

将二进制文件直接写入文件 I/O

import requests

img_url = 'https://techcrunch.com/wp-content/uploads/2023/03/dpreview.jpg'

response = requests.get(img_url, stream=True) 

with open('dpreview.jpg', 'wb') as fout:
    for chunk in response:
        fout.write(chunk)
Run Code Online (Sandbox Code Playgroud)

将内容流式传输io.BytesIO到对象中PIL.Image并保存

from io import BytesIO

import requests
from PIL import Image

img_url = 'https://techcrunch.com/wp-content/uploads/2023/03/dpreview.jpg'

# Stream to BytesIO
response = requests.get(img_url, stream=True)
img = Image.open(BytesIO(response.content))
img.save('dpreview.jpg')


# Using raw content
response = requests.get(img_url, stream=True)
img = Image.open(response.raw)
img.save('dpreview.jpg')

Run Code Online (Sandbox Code Playgroud)

使用urllib

原始答案来自/sf/answers/2370628781/

import urllib

img_url = 'https://techcrunch.com/wp-content/uploads/2023/03/dpreview.jpg'

urllib.request.urlretrieve(img_url, "dpreview.jpg")
Run Code Online (Sandbox Code Playgroud)

如果请求需要特定的用户代理,请来自/sf/answers/4883546601/

import urllib

opener=urllib.request.build_opener()
opener.addheaders=[('User-Agent','Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19582')]
urllib.request.install_opener(opener)

img_url = 'https://techcrunch.com/wp-content/uploads/2023/03/dpreview.jpg'

urllib.request.urlretrieve(img_url, "dpreview.jpg")
Run Code Online (Sandbox Code Playgroud)

使用wget

import wget

img_url = 'https://techcrunch.com/wp-content/uploads/2023/03/dpreview.jpg'

wget.download(img_url, out='dpreview.jpg')
Run Code Online (Sandbox Code Playgroud)

保存PIL.Imagenumpy数组

import requests
from PIL import Image

import numpy as np


img_url = 'https://techcrunch.com/wp-content/uploads/2023/03/dpreview.jpg'

response = requests.get(img_url, stream=True) 
img = Image.open(response.raw)

# Converts and save image into numpy array.
np.save('dpreview.npy', np.asarray(img))

# Loads a npy file to Image
img_arr = np.load('dpreview.npy')
img = Image.fromarray(img_arr.astype(np.uint8))
Run Code Online (Sandbox Code Playgroud)


Chr*_*ord 5

这是一个更用户友好的答案,仍然使用流媒体。

只需定义这些函数并调用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')
Run Code Online (Sandbox Code Playgroud)

request的胆量getImage()是基于答案在这里和胆量getImageFast()是基于答案以上


jus*_*ncc 5

我将发布一个答案,因为我没有足够的代表来发表评论,但是使用 Blairg23 发布的 wget,您还可以为路径提供一个 out 参数。

 wget.download(url, out=path)
Run Code Online (Sandbox Code Playgroud)


小智 5

这就是我做到的

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()
Run Code Online (Sandbox Code Playgroud)


Adr*_*fas 5

我的方法是使用response.content(blob)并以二进制模式保存到文件

img_blob = requests.get(url, timeout=5).content
with open(destination + '/' + title, 'wb') as img_file:
     img_file.write(img_blob)
Run Code Online (Sandbox Code Playgroud)

查看我的python 项目,该项目根据关键字从 unsplash.com 下载图像。