Python 如何使用请求下载图像

Python 如何使用请求下载图像,python,urllib2,python-requests,Python,Urllib2,Python Requests,我正在尝试使用python的请求模块从web下载并保存图像 以下是我使用的(工作)代码: img = urllib2.urlopen(settings.STATICMAP_URL.format(**data)) with open(path, 'w') as f: f.write(img.read()) 以下是使用请求的新(非工作)代码: r = requests.get(settings.STATICMAP_URL.format(**data)) if r.status_code =

我正在尝试使用python的
请求
模块从web下载并保存图像

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

img = urllib2.urlopen(settings.STATICMAP_URL.format(**data))
with open(path, 'w') as f:
    f.write(img.read())
以下是使用
请求的新(非工作)代码:

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)
您可以帮助我从
请求中使用响应中的哪些属性吗?

您可以使用,也可以迭代响应

使用
response.raw
类文件对象默认情况下不会对压缩响应进行解码(使用GZIP或deflate)。通过将
decode\u content
属性设置为
True
requests
将其设置为
False
以控制解码本身),您可以强制它为您解压。然后,您可以使用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字节块读取数据;如果您觉得另一个块大小更有效,请使用具有自定义块大小的:

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
,以便
请求
不会首先将整个图像下载到内存中。

从请求中获取类似文件的对象,并将其复制到文件中。这样也可以避免一次将整件事情读入内存

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

我同样需要使用请求下载图像。我首先尝试了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

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

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)

这里有一个更加用户友好的答案,仍然使用流媒体

只需定义这些函数并调用
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')

请求
getImage()
的胆量基于答案,而
getImageFast()
的胆量基于答案。

这可能比使用
请求更容易。这是我唯一一次建议不要使用
请求
来处理HTTP内容

使用
urllib
的两行程序:

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

还有一个很好的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'
享受

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

>>> out_filepath = <output_filepath>    
>>> filename = wget.download(url, out=out_filepath)
>>输出文件路径=
>>>filename=wget.download(url,out=out\u文件路径)

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

 wget.download(url, out=path)
主要有两种方式:

  • 使用
    .content
    (最简单/官方)(请参阅):

  • 使用
    .raw
    (请参阅):


  • 计时两者没有明显的区别。

    下面的代码片段下载一个文件

    文件以指定的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)
    

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

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

    您可以这样做:

    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)
    

    这是谷歌搜索关于如何下载带有请求的二进制文件的第一个响应。如果您需要下载带有请求的任意文件,您可以使用:

    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)
    
    我就是这样做的

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

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

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

    查看我的基于关键字从unsplash.com下载图像的网站。

    要使用r.raw,您需要设置stream=true这是否回答了您的问题?非常感谢您回来回答这个问题。尽管另一个答案是可行的,但这一个是跨越式的simplerIt值得注意的是,很少有服务器将其图像设置为GZIP,因为图像已经有了自己的压缩。这会适得其反,浪费CPU周期而没有什么好处。因此,虽然这可能是文本内容的问题,特别是图像的问题,但事实并非如此。我们有没有办法访问原始内容filename@phette23另外值得注意的是,Google PageSpeed在默认情况下会报告并执行此操作。应在
    shutil.copyfileobj(response.raw,out\u文件)之前设置
    r.raw.decode\u content=True
    因为默认情况下,
    解码压缩响应(使用GZIP或deflate)
    ,所以您将获得零文件图像。这是因为您没有指定默认为1的
    chunk\u size
    参数,所以
    iter\u content
    在结果流上一次迭代1个字节。请参阅文档。这也会将整个响应加载到内存中,您可能希望避免这样做。这里也没有使用
    PIL
    ,只需
    将open(image_name,'wb')作为outfile:outfile.write(r.content)
    就足够了。
    PIL
    也不在标准库中,这使得它的可移植性稍差。@ZhenyiZhang
    iter_content
    速度慢,因为
    块大小
    太小,如果将其增加到100k,速度会快得多。根据请求作者
    http://docs.python-requests.org/en/latest/user/quickstart/#binary-响应内容
    在您的回答的帮助下,我可以在文本文件中找到数据,我使用的步骤是
    r2=requests.post(r.url,data);打印r2.内容
    。但现在我还想知道
    文件名
    。他们的方法干净吗?--目前,我在头文件--
    r2.headers['content-disposition']
    中找到了文件名,它给出了输出
    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()
    
    img_blob = requests.get(url, timeout=5).content
         with open(destination + '/' + title, 'wb') as img_file:
             img_file.write(img_blob)