图片的尺寸信息一般都在图片文件的头部几个字节内,所以只下载头部几个字节即可获得图片的尺寸,这也是为什么浏览器在图片还未加载完成即可正确显示图片的尺寸的原因。
使用PIL获取图片尺寸
1
2
3
4
5
6
7
8
from PIL import Image
def get_size(fn):
try:
img = Image.open(fn)
return img.size
except Exception as e:
return (0, 0)
使用 requests 下载数据流,使用 BytesIO 把数据流暂存到内存中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from io import BytesIO
import requests
from PIL import Image
def get_size(fn):
try:
img = Image.open(fn)
return img.size
except Exception:
return (0, 0)
def stream():
# 用于保存图片头部字节流
head = BytesIO()
# stream=True 表示数据流方式下载
r = requests.get(
'https://img30.360buyimg.com/sku/jfs/t1/184915/21/23329/362021/624fa58eE6b2ae8bc/1f17196eb4537d48.jpg', stream=True)
# 每次下载的数据大小,经测试2KB左右,可以获得图片尺寸的成功率较为理想
chunk_size = 1024 * 2
if r.status_code == 200:
for chunk in r.iter_content(chunk_size):
head.write(chunk)
print(get_size(head))
r.close()
stream()
# 输出结果 (750, 1129)
使用 aiohttp_requests 实现的异步版本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from awaits.awaitable import awaitable
from aiohttp_requests import requests as io_requests
import asyncio
from io import BytesIO
from PIL import Image
@awaitable
def get_size(fn):
try:
img = Image.open(fn)
return img.size
except Exception as e:
return (0, 0)
async def stream():
head = BytesIO()
chunk_size = 1024 * 2
url = 'https://img30.360buyimg.com/sku/jfs/t1/184915/21/23329/362021/624fa58eE6b2ae8bc/1f17196eb4537d48.jpg'
r = await io_requests.get(url)
if r.status == 200:
is_first = True
async for chunk in r.content.iter_chunked(chunk_size):
head.write(chunk)
size = await get_size(head)
print(size)
await r.wait_for_close()
break
asyncio.run(stream())