Retrieve JPG pictures from URL (Python)
-
02-07-2021 - |
Question
I'm trying to retrieve JPG images from http ULRs (to display them in a GUI) with the following Python code:
import urllib3
from cStringIO import StringIO
from PIL import Image
conn = urllib3.connection_from_url('http://www.solarspace.co.uk/')
img_file = conn.urlopen('GET', 'http://www.solarspace.co.uk/PlanetPics/Neptune/NeptuneAlt1.jpg')
image = StringIO(img_file.read())
image.seek(0)
resized_image = Image.open(image)
However, this gives me this error message: "IOError: cannot identify image file".
The reason why I'm using urllib3 is because I need a persistent connection (to send multiple requests), which is not available with urllib/urllib2.
Thanks in advance.
Solution
Seems to work if you use img_file.data
instead of img_file.read()
. img_file.read()
is meant to be used when you specify preload_content=False
on the request. Now that I think about it, it's not very intuitive, perhaps img_file.read()
should be aware of the cached preloaded content, or perhaps it should raise an exception if it has already been consumed. The plan was to make preload_content=False
default but turns out there are a lot of edge cases which fall under normal usage that are hard to satisfy. I opened a bug to fix this in the future: https://github.com/shazow/urllib3/issues/102
Anyways, using img_file.data
should fix your problem. Sorry for the confusion! :)
Also I suggest using conn.request(...)
instead of the lower-level conn.urlopen(...)
, and perhaps use PoolManager
if you might be going cross-domain (no reason not to use it, really). Try this:
>>> http = urllib3.PoolManager()
>>> r = http.request('GET', 'http://www.solarspace.co.uk/PlanetPics/Neptune/NeptuneAlt1.jpg')
>>> resized_image = Image.open(StringIO(r.data))
OTHER TIPS
As always, requests
to the rescue:
>>> r = requests.get('http://www.solarspace.co.uk/PlanetPics/Neptune/NeptuneAlt1.jpg')
>>> i = Image.open(StringIO.StringIO(r.content))
>>> i.size
(262, 299)
When save it, you can do:
with open('##.jpg','wb') as fout:
fout.write(r.content)