Python批量提取Word文档图片与嵌入文件实战
简介这份资源面向需要用Python自动化处理Word文档的开发者与办公自动化爱好者聚焦于从.docx文件中批量导出内嵌图片与OLE嵌入文件这一具体问题。包内共2033个文件以908个py源码、880个pyc字节码为主辅以C扩展头文件、pyd动态库、exe可执行文件及少量docx示例文档压缩包约12.42MB并附带虚拟环境与IDE配置开箱即可运行调试。实现思路上借助docx库遍历段落、表格等元素定位图片解析关系文件获取图片数据并落盘对嵌入的Excel、PDF等对象则通过oletools等库解析OLE结构完成提取脚本分工清晰便于二次改造。已有1197人学习下载适合希望掌握文档深度解析、批量迁移与内容整理技巧的读者参考借鉴。1. 批量提取 Word 文档里的图片和嵌入文件Python 这条路走得通做过文档迁移的同行大概都遇到过这种需求手头几十上百个.docx文件里面散落着产品图、截图、附件表格业务方要你把它们全部抽出来归档。手动右键另存一个文件还能忍一百个就是纯体力活。这个项目的定位很明确——用 Python 把 Word 文档里的图片和嵌入对象批量导出适合需要做文档资产整理、内容迁移或二次开发的开发者。它不依赖 Office 软件本身纯代码解析.docx包结构跑在服务器上也没问题。技术栈就是 Python 标准库zipfile加xml解析配合python-docx处理文档关系映射轻量、可嵌入、好改造。下面从目录结构一路拆到核心代码再讲怎么改。2. 项目结构与技术选型为什么不用 COM 接口2.1 目录布局与模块职责这个项目的代码量不大但分层清晰适合直接嵌进现有工程。典型目录结构如下word-extractor/ ├── extractor/ │ ├── __init__.py │ ├── core.py # 主提取逻辑协调各模块 │ ├── media.py # 图片资源定位与导出 │ ├── embedded.py # 嵌入文件OLE对象处理 │ └── rels.py # 关系映射解析 ├── utils/ │ ├── file_utils.py # 文件读写、目录创建 │ └── logger.py # 日志配置 ├── config.py # 输出路径、命名规则等配置 ├── main.py # 命令行入口 └── requirements.txtcore.py是调度中心负责打开.docx、调用关系解析、分发到media.py或embedded.py。rels.py单独抽出来是因为.docx内部的关系映射word/_rels/document.xml.rels决定了每个资源文件的真实路径和类型这是整个提取流程的关键索引。config.py集中管理输出目录、文件名模板、是否保留原始目录层级等参数改起来不用翻业务代码。2.2 技术选型zipfile lxml 而非 COM很多人第一反应是用win32com调 Word 的 COM 接口让 Office 自己另存。这条路在 Windows 桌面环境下能跑但问题很明显必须装 Office、启动慢、并发差、服务器上基本没法用。这个项目选了另一条路——.docx本质上就是一个 ZIP 包图片放在word/media/下嵌入文件放在word/embeddings/下关系映射写在word/_rels/document.xml.rels里。用zipfile直接读包用lxml解析 XML不依赖任何外部软件。import zipfile from lxml import etree def open_docx(path): 打开 docx 文件返回 zip 对象和关系映射字典 zf zipfile.ZipFile(path, r) # 读取关系映射文件建立 rId - 目标路径的索引 rels_xml zf.read(word/_rels/document.xml.rels) root etree.fromstring(rels_xml) rels_map {} for rel in root: rid rel.get(Id) target rel.get(Target) rel_type rel.get(Type) rels_map[rid] {target: target, type: rel_type} return zf, rels_map这段代码是整个提取流程的入口。zipfile.ZipFile以只读模式打开文档zf.read直接读取内部 XML 而不解压到磁盘。rels_map的键是关系 ID如rId5值包含目标路径和类型。类型字段用来区分是图片、嵌入文件还是超链接——图片的 Type 通常以/image结尾嵌入对象的 Type 包含/oleObject。拿到这个映射后后续就能根据文档正文里引用的rId反查真实文件路径。注意.doc老格式不是 ZIP 包这套方法只适用于.docx。如果手头有.doc需要先批量转成.docx常见做法是用 LibreOffice 的无头模式转换。2.3 依赖清单与版本约束requirements.txt里核心依赖只有两个lxml用于 XML 解析python-docx用于高层文档遍历。python-docx本身也依赖lxml所以实际安装时版本要统一。我一般会锁定lxml4.9和python-docx0.8.11这两个版本组合在 Python 3.8 到 3.11 上都验证过。如果只需要底层提取其实可以完全不用python-docx直接用zipfilelxml就够了少一层依赖少一个坑。3. 核心提取逻辑从关系映射到文件落盘3.1 图片提取定位 media 目录并导出图片提取的关键是两步先从关系映射里筛出所有图片类型的关系再根据 Target 路径从 ZIP 包里读出二进制流写盘。media.py里的核心函数如下import os from utils.file_utils import ensure_dir IMAGE_TYPES (image/png, image/jpeg, image/gif, image/bmp) def extract_images(zf, rels_map, output_dir): 从 docx 中提取所有图片到 output_dir ensure_dir(output_dir) count 0 for rid, info in rels_map.items(): # 只处理图片类型的关系 if not any(t in info[type] for t in IMAGE_TYPES): continue target info[target] # Target 可能是相对路径需要拼上 word/ 前缀 if not target.startswith(word/): target word/ target.lstrip(/) try: data zf.read(target) except KeyError: continue # 关系存在但文件缺失跳过 # 用原始文件名保存避免重名加 rId 前缀 filename f{rid}_{os.path.basename(target)} with open(os.path.join(output_dir, filename), wb) as f: f.write(data) count 1 return countIMAGE_TYPES定义了支持的图片 MIME 类型实际项目中可能还需要加image/tiff或image/webp。info[type]是完整的关系类型 URI用in做子串匹配比精确匹配更稳因为不同 Word 版本生成的 URI 前缀可能略有差异。target字段在关系文件里通常是相对word/的路径比如media/image1.png所以需要补全前缀。zf.read如果遇到关系存在但实际文件缺失的情况会抛KeyError这里直接跳过而不是中断整个流程——批量处理时一个坏文件不应该拖垮全部任务。文件名用rId加原始文件名既保留了顺序信息又避免不同图片重名覆盖。3.2 嵌入文件提取OLE 对象与包对象嵌入文件比图片复杂一些因为 Word 里插入的 Excel 表格、PDF 附件、另一个 Word 文档在底层可能以 OLE 对象或包对象的形式存在。它们的共同点是都放在word/embeddings/目录下但关系类型不同。EMBED_TYPES (oleObject, package) def extract_embedded(zf, rels_map, output_dir): 提取嵌入的 OLE 对象和包对象 ensure_dir(output_dir) results [] for rid, info in rels_map.items(): if not any(t in info[type] for t in EMBED_TYPES): continue target info[target] if not target.startswith(word/): target word/ target.lstrip(/) try: data zf.read(target) except KeyError: continue # 嵌入文件的原始扩展名藏在 oleObject 的 progId 里 # 这里先用 bin 后缀保存后续可根据 progId 重命名 filename f{rid}_{os.path.basename(target)} with open(os.path.join(output_dir, filename), wb) as f: f.write(data) results.append({rid: rid, file: filename, size: len(data)}) return resultsEMBED_TYPES覆盖了oleObject和package两种关系类型。嵌入文件在 ZIP 包里的实际文件名通常是oleObject1.bin、oleObject2.bin这种没有扩展名。要还原成可打开的文件需要进一步解析word/embeddings/下对应的 XML 描述文件从中读取progId如Excel.Sheet.12来推断真实格式。这个项目里先以.bin保存把重命名逻辑留给二次开发按需实现——因为不同业务对嵌入文件的处理策略差异很大有的要还原成 Excel有的只要原始二进制归档。3.3 关系映射解析rId 与真实路径的桥梁rels.py负责把关系映射解析成更易用的结构同时处理一些边界情况比如外部链接Target 是 URL 而非内部路径和图片在页眉页脚中的引用。def build_resource_index(rels_map): 把关系映射按类型分组返回 {type: [资源列表]} index {images: [], embedded: [], others: []} for rid, info in rels_map.items(): target info[target] # 跳过外部链接只处理包内资源 if target.startswith(http) or target.startswith(mailto): continue rel_type info[type] if image in rel_type: index[images].append({rid: rid, target: target}) elif oleObject in rel_type or package in rel_type: index[embedded].append({rid: rid, target: target}) else: index[others].append({rid: rid, target: target}) return index这个索引结构让上层调用更清晰core.py拿到index后直接按类别分发不用在每个提取函数里重复判断类型。跳过http和mailto开头的外部链接很重要否则会尝试从 ZIP 包里读一个不存在的路径而报错。others类别里可能包含超链接、批注引用等当前项目不处理但保留结构方便扩展。4. 避坑与常见问题排查4.1 提取出来图片打不开或只有几 KB现象导出的 PNG 文件大小异常用看图软件打开提示损坏。原因通常是关系映射里的 Target 路径没有正确补全前缀导致读到了错误的文件或者读的是缩略图而非原图。.docx里图片可能同时存在原图和缩略图两个关系缩略图在word/media/下但尺寸很小。解决在extract_images里加一层过滤检查文件大小小于 1KB 的跳过同时打印每个 Target 的实际路径确认补全逻辑正确。4.2 嵌入的 Excel 文件导出后无法打开现象oleObject1.bin改成.xlsx后 Excel 报格式错误。原因是 OLE 对象外面包了一层复合文档结构不是直接的 xlsx 二进制。解决需要解析word/embeddings/下对应的.xml描述文件读取progId和shapeId再用olefile库剥离外层容器。如果业务只要求归档原始数据保持.bin后缀不强行改扩展名反而更安全。4.3 批量处理时某个文件报错导致整个任务中断现象跑一百个文档跑到第 37 个抛异常后面全部没处理。原因是zipfile或lxml遇到损坏文件时抛出的异常没有被捕获。解决在main.py的循环里对每个文件单独 try-except记录失败文件名和异常信息到日志继续处理下一个。批量任务的铁律是单个失败不影响整体最后统一汇总失败列表。4.4 中文文件名乱码现象导出的图片文件名里中文变成乱码。原因是 ZIP 包内文件名编码在不同 Word 版本下不一致zipfile默认用 CP437 解码。解决在ZipFile构造时传入metadata_encodingutf-8Python 3.11 支持或者手动对namelist()里的文件名做编码转换。更稳妥的做法是导出时不用原始文件名统一用rId加序号命名彻底绕开编码问题。4.5 页眉页脚里的图片提取不到现象正文图片都导出了但页眉里的 Logo 没出来。原因是页眉页脚有独立的关系映射文件路径在word/_rels/header1.xml.rels等位置不在主文档的document.xml.rels里。解决遍历word/_rels/下所有.rels文件合并关系映射后再统一提取。这个改动不大但能覆盖更完整的场景。5. 二次开发改造从能跑到好用5.1 按文档结构还原图片位置当前实现是把所有图片平铺到一个目录实际业务里往往需要知道每张图在文档中的位置——比如按章节归档或者生成一份「图片-段落」对照表。改造思路是解析word/document.xml遍历所有w:drawing节点从中提取r:embed属性拿到rId再结合段落文本和标题层级建立映射。from lxml import etree NS { w: http://schemas.openxmlformats.org/wordprocessingml/2006/main, r: http://schemas.openxmlformats.org/officeDocument/2006/relationships, a: http://schemas.openxmlformats.org/drawingml/2006/main } def map_images_to_paragraphs(zf): 返回 [(段落文本, rId), ...] 的映射列表 doc_xml zf.read(word/document.xml) root etree.fromstring(doc_xml) result [] for para in root.iter({http://schemas.openxmlformats.org/wordprocessingml/2006/main}p): text .join(para.itertext()).strip() for drawing in para.iter({http://schemas.openxmlformats.org/wordprocessingml/2006/main}drawing): for blip in drawing.iter({http://schemas.openxmlformats.org/drawingml/2006/main}blip): rid blip.get({http://schemas.openxmlformats.org/officeDocument/2006/relationships}embed) if rid: result.append((text[:50], rid)) return result这段代码遍历文档所有段落对每个段落查找内嵌的drawing节点再从中提取blip元素的r:embed属性。text[:50]截取段落前 50 个字符作为位置标识避免长段落撑爆输出。拿到这个映射后导出图片时就可以按段落文本生成子目录或者输出一份 CSV 索引。5.2 输出格式与命名策略的可配置化不同项目对输出结构要求不同有的要按原始media目录结构保留有的要按扩展名分目录有的要加时间戳前缀。建议在config.py里定义命名策略函数而不是硬编码在提取逻辑里。配置项可选值说明namingrid/original/index文件名生成规则subdir_bynone/ext/type是否按扩展名或类型建子目录keep_structureTrue/False是否保留原始 media 目录层级overwriteTrue/False同名文件是否覆盖我一般会把naming默认设为rid因为原始文件名在批量场景下重名率极高rid加序号最稳。subdir_by设为ext在图片和嵌入文件混在一起时特别有用导出后一眼就能看出哪些是图、哪些是附件。5.3 验证提取完整性的一个笨办法改完代码怎么确认没漏我的习惯是对比 ZIP 包内word/media/和word/embeddings/下的文件总数与导出文件数。写个校验函数def verify_extraction(zf, output_dir): 对比包内资源数与导出数 internal [n for n in zf.namelist() if n.startswith(word/media/) or n.startswith(word/embeddings/)] exported [f for f in os.listdir(output_dir) if os.path.isfile(os.path.join(output_dir, f))] print(f包内资源: {len(internal)}, 已导出: {len(exported)}) if len(internal) ! len(exported): missing set(os.path.basename(n) for n in internal) - set(exported) print(f可能遗漏: {missing})这个校验不判断内容是否正确只保证数量对齐。数量对不上时missing集合能直接指出哪些文件没导出来再去查对应的关系映射就能定位问题。从那以后我每次改完提取逻辑都强制走一遍这个校验比肉眼翻目录靠谱得多。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

HCNA 912题网络基础梳理:OSI、IP编址与VLAN易错点

HCNA 912题网络基础梳理:OSI、IP编址与VLAN易错点

简介:这是一份面向华为HCNA/HCDA认证考生的题库资料,共912道真题及答案,覆盖IP地址与子网掩码计算、PPP与数据链路层协议、OSI模型、TCP/UDP传输层协议、VLAN与STP等核心考点,适合备考冲刺和基础知识查漏补缺。资料为单PDF文件&am…

2026/10/18 10:02:38 阅读更多 →
Il2CppDumper v6.7.46:Unity IL2CPP元数据恢复核心工具

Il2CppDumper v6.7.46:Unity IL2CPP元数据恢复核心工具

简介:Il2CppDumper-win-v6.7.46 是一款面向Unity逆向分析工程师与安全研究人员的成熟IL2CPP逆向工具集,专为还原Unity原生构建(il2cpp)产物中的类型结构与元数据而设计,适用于Unity 5.3至2020版本的Android&#xff08…

2026/10/18 10:01:37 阅读更多 →
局域网组网入门:从冲突域和广播域到设备选型与配置

局域网组网入门:从冲突域和广播域到设备选型与配置

简介:一份计算机网络课程设计报告,主题为局域网组网,适合高校计算机、人工智能等专业学生参考。压缩包仅含1个Word文档(docx格式),约562KB,以完整报告正文与目录结构呈现,便于阅读、…

2026/10/18 10:01:37 阅读更多 →

最新新闻

PFA算法:基于正交投影一致性的多模态特征空间隐式对齐

PFA算法:基于正交投影一致性的多模态特征空间隐式对齐

简介:本资源为数据挖掘领域Pattern Fusion(PFA)算法的完整实践套件,面向算法研究者、R/ MATLAB开发者及高年级本科生或研究生,聚焦于大规模频繁模式的精炼提取与融合优化问题。资源共23个文件,涵盖9个txt&a…

2026/10/18 10:47:51 阅读更多 →
Flex布局对齐三兄弟:justify-content、align-items、align-content详解

Flex布局对齐三兄弟:justify-content、align-items、align-content详解

Flex 布局这个系列写到第三篇,前面已经把容器的 display、flex-direction、flex-wrap 这些基础概念过了一遍。评论区不少读者留言说,最头疼的就是 justify-content、align-items、align-content 这三个属性,看起来都是“对齐”,但…

2026/10/18 10:47:51 阅读更多 →
基于深度学习的故障诊断模型代码与数据:从振动信号到故障分类的完整流程

基于深度学习的故障诊断模型代码与数据:从振动信号到故障分类的完整流程

简介:这份资源面向深度学习与工业故障诊断方向的研究者和工程师,提供一套可直接运行的故障诊断模型代码与配套数据,帮助读者跳过从零搭建系统的环节,快速进入模型训练与实验验证阶段。压缩包共63个文件,约57.74MB&…

2026/10/18 10:47:51 阅读更多 →
流量分析实战指南:从抓包到行为识别,揪出内网异常

流量分析实战指南:从抓包到行为识别,揪出内网异常

上个月在一家客户的内部网络做审计时,我盯着核心交换机的镜像口看了十分钟,注意到一台内网服务器每隔四十分钟就会产生一次几百KB的外联流量。连接数不多,时长不长,但雷打不动的周期让人很不舒服。顺着这条线往下查,最…

2026/10/18 10:47:51 阅读更多 →
知识付费v4.5.4源码解析:一套系统搞定PC、H5、小程序和APP

知识付费v4.5.4源码解析:一套系统搞定PC、H5、小程序和APP

简介:知识付费v4.5.4源码是面向在线教育与知识变现场景的一整套私有化部署方案,主要服务于培训机构、独立讲师和想搭建网校的站长。系统一套代码同时覆盖PC端、H5网页与微信小程序,支持直播、录播、图文、考试练习等多元教务形式,…

2026/10/18 10:47:50 阅读更多 →
KAN与六种神经网络架构结合实战:图像分类与时间序列预测对比

KAN与六种神经网络架构结合实战:图像分类与时间序列预测对比

最近一直在做时间序列预测和图像分类的实验,发现朋友圈里聊天总绕不开KAN(Kolmogorov-Arnold Network)这个词。有同学拿"KAN全面吊打MLP"的截图来问我是不是真能替换掉手头的模型,也有同学问KAN跟CNN、LSTM、TCN、Transformer这些经典结构组合之后到底效果怎么样、代…

2026/10/18 10:46:50 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →