如何使用请求下载图片

我试图从网上下载并保存一个图像使用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属性吗?

你可以使用response.raw文件对象 ,或迭代响应。

要使用response.raw文件对象,默认情况下不会解码压缩的响应(使用GZIP或放气)。 你可以通过设置decode_content属性为Truerequests将它设置为False来控制解码本身)来强制它解压缩。 然后你可以使用shutil.copyfileobj()让Python把数据stream传给一个文件对象:

 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不首先将整个图像下载到内存中。

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

 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的回答,而且效果很好。 但是当我在这个简单的函数上做一个configuration文件时,我发现它比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)) 

这大大减less了函数调用的次数,从而加速了我的应用程序。 这是我的分析器和结果的代码。

 #!/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 

这个怎么样,一个快速的解决scheme。

 import requests url = "http://craphound.comhttp://img.dovov.com1006884_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) 

这可能比使用requests更容易。 这是我唯一一次build议不要使用HTTP requests

使用urllib两个class轮:

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

还有一个很好用的Python模块,叫做wget 。 在这里find。

这表明了devise的简单性:

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

请享用。

编辑:你也可以添加一个out参数来指定一个path。

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

以下代码片段下载一个文件。

该文件与其文件名保存在指定的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) 

主要有两种方式:

  1. 使用.content (最简单/官方)(见张振一的答案 ):

     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. 

时间都没有显着差异。

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

只需定义这些函数并调用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()request是基于这里的答案和getImageFast()是基于上面的答案。

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

  wget.download(url, out=path)