2016-06-10 50 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