2016-06-10 51 views
1

我想下载一个原始图像(PNG格式)的网址,转换它在飞行(不保存到光盘)并保存为JPG格式。下载图像与PIL和请求

的代码如下:

import os 
import io 
import requests 
from PIL import Image 
... 
r = requests.get(img_url, stream=True) 
if r.status_code == 200: 
    i = Image.open(io.BytesIO(r.content)) 
    i.save(os.path.join(out_dir, 'image.jpg'), quality=85) 

它的工作原理,但是当我尝试监视下载进度(为将来的进度条)与r.iter_content()这样的:

r = requests.get(img_url, stream=True) 
if r.status_code == 200: 
    for chunk in r.iter_content(): 
     print(len(chunk)) 
    i = Image.open(io.BytesIO(r.content)) 
    i.save(os.path.join(out_dir, 'image.jpg'), quality=85) 

我得到这个错误:

Traceback (most recent call last): 
    File "E:/GitHub/geoportal/quicklookScrape/temp.py", line 37, in <module> 
    i = Image.open(io.BytesIO(r.content)) 
    File "C:\Python35\lib\site-packages\requests\models.py", line 736, in content 
    'The content for this response was already consumed') 
RuntimeError: The content for this response was already consumed 

所以有可能监视下载进度和获得数据后本身?

回答

2

使用r.iter_content()时,需要在某处缓存结果。不幸的是,我找不到任何内容附加到内存中的对象的例子 - 通常,当一个文件不能或不应该一次加载到内存中时,通常会使用iter_content。但是,您可以使用tempfile.SpooledTemporaryFile进行缓冲,如本答案所述:https://stackoverflow.com/a/18550652/4527093。这将防止将映像保存到磁盘(除非映像大于指定的max_size)。然后,您可以从tempfile创建Image

import os 
import io 
import requests 
from PIL import Image 
import tempfile 

buffer = tempfile.SpooledTemporaryFile(max_size=1e9) 
r = requests.get(img_url, stream=True) 
if r.status_code == 200: 
    downloaded = 0 
    filesize = int(r.headers['content-length']) 
    for chunk in r.iter_content(): 
     downloaded += len(chunk) 
     buffer.write(chunk) 
     print(downloaded/filesize) 
    buffer.seek(0) 
    i = Image.open(io.BytesIO(buffer.read())) 
    i.save(os.path.join(out_dir, 'image.jpg'), quality=85) 
buffer.close() 
+0

非常感谢dbc!而如果我只是使用普通的TemporaryFile呢? '用TemporaryFile()作为tempf:',将'chunks'写入它,然后用'i = Image.open(tempf)'读取它?这不是更容易吗? – Vasily

+1

这是行得通的,但使用'TemporaryFile'实际上将字节写入到磁盘中。使用'SpooledTemporaryFile'将字节保存在内存中,因此可能会更快 - 并且这是您在问题中指定的内容。 :) – dbc