本文介绍如何利用 Python 的 zipfile 和 lxml 库,直接解析 Excel .xlsx 文件内部 XML,高效提取形状(如文本框、椭圆)的几何类型、填充色和边框色,无需依赖耗时的 COM 或自动化库。
本文介绍如何利用 python 的 `zipfile` 和 `lxml` 库,直接解析 excel `.xlsx` 文件内部 xml,高效提取形状(如文本框、椭圆)的几何类型、填充色和边框色,无需依赖耗时的 com 或自动化库。
Excel 的 .xlsx 文件本质上是一个 ZIP 压缩包,其中形状(Shapes)的样式信息(包括颜色、形状类型、线条粗细等)均存储在 xl/drawings/drawing*.xml 文件中,遵循 Office Open XML 标准。与仅提取文本不同,获取颜色需定位 <xdr:spPr>(shape properties)节点下的 <a:solidFill>(填充)和 <a:ln>(线条)子节点,并读取其 <a:srgbClr/@val> 属性值(十六进制 RGB,如 '729fcf')。
以下为完整增强版代码,支持同时提取形状文本、几何类型(如 ellipse, rect)、填充色(fill color)和边框色(line color):
from zipfile import ZipFile
from lxml import etree
def extract_shapes_with_color(xlsx_path):
ns = {
"xdr": "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing",
"a": "http://schemas.openxmlformats.org/drawingml/2006/main",
"r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
}
shapes_data = []
with ZipFile(xlsx_path) as z:
# 查找所有 drawing XML 文件(如 drawing1.xml, drawing2.xml)
drawing_files = [f for f in z.filelist if "xl/drawings/drawing" in f.filename and f.filename.endswith(".xml")]
for drw in drawing_files:
with z.open(drw.filename) as f:
tree = etree.fromstring(f.read())
# 提取所有形状的文本内容(要求有 txBody 且前置 spPr)
texts = tree.xpath('//xdr:txBody[preceding-sibling::xdr:spPr]/a:p/a:r/a:t/text()', namespaces=ns)
# 提取对应形状的属性:几何类型、填充色、边框色(按顺序一一对应)
# 注意:XPath 返回扁平列表,需按每3个元素分组(prst, fill, line)
shape_attrs = tree.xpath(
'//xdr:spPr/a:prstGeom/@prst | '
'//xdr:spPr/a:solidFill/a:srgbClr/@val | '
'//xdr:spPr/a:ln/a:solidFill/a:srgbClr/@val',
namespaces=ns
)
# 按每3项分组:[geom, fill, line] → 与 texts 位置对齐(假设一一对应)
for i, text in enumerate(texts):
geom = shape_attrs[i*3] if i*3 < len(shape_attrs) else None
fill = shape_attrs[i*3+1] if i*3+1 < len(shape_attrs) else None
line = shape_attrs[i*3+2] if i*3+2 < len(shape_attrs) else None
shapes_data.append({
"text": text.strip() if text else "",
"geometry": geom,
"fill_color": fill, # 如 '729fcf' → #729fcf
"line_color": line # 如 '3465a4' → #3465a4
})
return shapes_data
# 使用示例
if __name__ == '__main__':
result = extract_shapes_with_color('/home/luis/tmp/shapes.xlsx')
for shape in result:
print(f"文本: '{shape['text']}' | 类型: {shape['geometry']} | "
f"填充色: #{shape['fill_color'] or 'N/A'} | "
f"边框色: #{shape['line_color'] or 'N/A'}")注意事项与说明:
- ✅ 性能优势:全程纯内存解析 XML,无外部进程或 COM 调用,处理千级形状仍保持毫秒级响应;
- ⚠️ 匹配假设:当前逻辑默认 texts 与 shape_attrs 中三元组顺序严格一致(即第 n 个文本对应第 n 组几何/填充/边框)。若实际 XML 中存在无文本的形状(如纯图形),建议改用更鲁棒的 XPath 关联方式(例如通过 xdr:sp 的 @macro 或 r:id 关联 xdr:txBody);
- ? 调试技巧:可手动解压 .xlsx 文件,打开 xl/drawings/drawing1.xml,用浏览器 DevTools 或 VS Code 的 XML 插件查看结构,右键复制 XPath 进行验证;
- ? 颜色格式:@val 值为小写六位十六进制(如 'ff0000' 表示红色),可直接用于 CSS 或 matplotlib;若需 RGB 元组,可用 tuple(int(c[i:i+2], 16) for i in (0,2,4)) 转换;
- ? 扩展提示:除 a:srgbClr/@val 外,部分形状可能使用 a:sysClr 或主题色(a:themeClr),需额外处理;透明度(a:alpha)亦可沿相同路径提取。
该方法兼顾简洁性与可维护性,是批量分析 Excel 图形样式的推荐实践。


















