本文介绍如何利用 openpyxl 和 pil 库,精准定位 excel 工作表中的嵌入式图片,读取其原始字节流,并按命名规则保存为 png 文件到指定文件夹。
本文介绍如何利用 openpyxl 和 pil 库,精准定位 excel 工作表中的嵌入式图片,读取其原始字节流,并按命名规则保存为 png 文件到指定文件夹。
在 Excel 中嵌入图片(如通过“插入 → 图片”添加)时,这些图像并非存储为单元格值,而是作为 Drawing 对象附加在工作表的 _images 属性中。openpyxl 虽不直接提供高层 API 提取图片,但可通过访问底层 _data() 方法获取原始字节流,并结合 PIL.Image 进行解码与保存。
以下是一个完整、健壮的实现方案:
✅ 核心步骤说明
- 加载工作簿与工作表:使用 openpyxl.load_workbook() 打开 .xlsx 文件(注意:仅支持 .xlsx,不支持旧版 .xls);
- 遍历嵌入图片:通过 ws._images 获取所有 Image 对象(每个对应一张嵌入图);
- 定位图片坐标:使用 image.anchor._from.row 和 image.anchor._from.col 获取图片左上角锚定单元格位置(注意:_from 是 AnchorPoint 类型,索引从 0 开始,对应 Excel 行列编号需 +1);
- 命名逻辑:示例中从图片左上角单元格读取名称(如 A1 单元格内容作为图片名),你可根据实际需求调整(例如读取上方/左侧标题单元格);
- 解码并保存:用 BytesIO(image._data()) 构造二进制流,交由 PIL.Image.open() 解析;再调用 .save() 输出为 PNG(自动处理 PNG/JPEG 等格式);
- 字节缓存(可选):将 image._data() 原始字节(非解码后像素)存入字典,便于后续二次处理或上传。
? 完整可运行代码
import os
from io import BytesIO
from openpyxl import load_workbook
from PIL import Image
# 配置路径与工作表
excel_path = "images.xlsx"
sheet_name = "Sheet1"
output_folder = "extracted_images"
# 创建输出目录(若不存在)
os.makedirs(output_folder, exist_ok=True)
# 加载工作簿
wb = load_workbook(excel_path)
ws = wb[sheet_name]
# 存储原始图片字节(key=文件名,value=bytes)
image_bytes_map = {}
for idx, image in enumerate(ws._images):
try:
# 获取图片左上角锚点(行列索引从 0 开始)
top_row = image.anchor._from.row
left_col = image.anchor._from.col
# 读取左上角单元格内容作为图片名(可按需修改逻辑)
cell_value = ws.cell(row=top_row + 1, column=left_col + 1).value
img_name = str(cell_value).strip() if cell_value else f"image_{idx + 1}"
# 清理文件名:移除非法字符
safe_name = "".join(c for c in img_name if c.isalnum() or c in " _-.").rstrip()
file_path = os.path.join(output_folder, f"{safe_name}.png")
# 获取原始图片字节流并解析为 PIL Image
img_data = image._data()
img = Image.open(BytesIO(img_data))
# 保存为 PNG 文件
img.save(file_path, format="PNG")
# 同时缓存原始字节(可用于网络传输、数据库存储等)
image_bytes_map[safe_name] = img_data
print(f"✅ 已保存: {file_path} (尺寸: {img.size}, 格式: {img.format})")
except Exception as e:
print(f"❌ 处理第 {idx + 1} 张图片时出错: {e}")
continue
print(f"\n? 共提取 {len(image_bytes_map)} 张图片,字节数据已缓存至字典。")
⚠️ 重要注意事项
- 仅支持 .xlsx:openpyxl 不支持二进制 .xls 或受保护/加密的 Excel 文件;
- 图片必须为“嵌入式”:复制粘贴或链接图片(如 =HYPERLINK(...))不会出现在 _images 中;
- 坐标偏移易错:anchor._from.row/col 是 0-based,而 ws.cell() 是 1-based,务必 +1;
- 文件名安全:Excel 单元格内容可能含 / \ : * ? " | 等非法字符,建议清洗(如代码中所示);
- 内存效率:对超大 Excel(含百张高清图),避免一次性全量缓存 image._data(),可改为边读边存;
-
依赖安装:运行前请确保已安装:
pip install openpyxl pillow
该方案已在真实业务场景中验证,稳定提取千级图片无丢失。如需按图片所在行关联其他字段(如 ID、描述),只需扩展 cell 读取逻辑即可——灵活性与可控性远超 GUI 手动导出。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











