Python批量导出Word文档图片与嵌入文件:基于zipfile的docx解包实战
简介这份资源面向需要用Python自动化处理Word文档的开发者与办公自动化爱好者聚焦于从.docx文件中批量导出内嵌图片与OLE嵌入文件这一常见却不易实现的场景。包内共2033个文件以908个py源码、880个pyc字节码为主辅以C扩展头文件、依赖元数据、可执行程序与说明文档压缩包约12.42MB其中docx_export.py与main.py承担核心导出逻辑虚拟环境与IDE配置也已一并打包开箱即可运行。资源围绕docx库解析文档关系、定位图片二进制数据并结合oletools等工具解析OLE结构提取嵌入的表格、PDF等对象形成完整的导出工作流。已有1197人学习下载适合希望掌握文档内容自动化提取、迁移与整理技巧的读者参考实践。1. 从一份 200 页的 Word 报告里把图抠出来为什么我最后选了 python-docx上周帮某实验室整理一份 200 多页的验收报告对方要我把里面所有插图和嵌入的附件单独导出来归档。我第一反应是手动另存为网页结果图片全糊了嵌入的 Excel 附件直接消失。后来试了 python-docx才发现 Word 的图片和嵌入文件根本不是存在文档正文里的而是藏在word/media/和word/embeddings/这两个目录下。这个资源就是围绕这个场景来的用 Python 把 .docx 里的图片和嵌入对象批量导出适合需要做文档归档、素材提取、报告拆解的从业者。它不处理 .doc 老格式也不做 OCR就是纯粹的解包和落盘。如果你手上有一堆 docx 要拆素材这套思路能省掉大量重复劳动。2. 拆开 docx 之前先搞懂它到底是个什么结构2.1 docx 本质是个 zip不是二进制黑匣子很多人以为 .docx 是 Word 专属的二进制格式其实从 Office 2007 开始它就是一个标准的 ZIP 压缩包里面按目录结构存放 XML 和资源文件。你把任意一个 .docx 的后缀改成 .zip用解压工具打开就能看到完整的内部结构。这个认知很关键因为它决定了后面所有操作的本质我们不是在“解析 Word”而是在“解压一个特定结构的压缩包再按需读取里面的资源”。常见的内部目录长这样路径存放内容word/document.xml正文内容段落、表格、文字都在这里word/media/所有嵌入的图片通常命名为 image1.png、image2.jpegword/embeddings/嵌入的 OLE 对象比如内嵌的 Excel、PDF、另一个 docxword/_rels/document.xml.rels关系映射表记录每个资源被谁引用[Content_Types].xml声明各扩展名对应的 MIME 类型图片和嵌入文件不会出现在 document.xml 的正文里正文里只有引用 ID真正的二进制数据在 media 和 embeddings 目录下。所以导出图片这件事本质上就是遍历这两个目录把文件复制出来。2.2 为什么不用 python-docx 的 API 直接取图python-docx 提供了document.inline_shapes可以拿到内联图片但它有两个硬伤第一它只能拿到内联图片浮动图片比如设置了文字环绕的拿不到第二它返回的是图片的引用关系不是原始二进制流遇到 EMF、WMF 这类矢量格式时经常报错。我一开始也图省事用 API结果一份报告里 30 张图只导出了 18 张剩下的全是浮动排版。后来改成直接操作 zip 包问题一次性解决。常见做法是用zipfile模块打开 docx先列出word/media/下所有文件再逐个读取字节流写出去。嵌入文件同理遍历word/embeddings/即可。这样做的好处是不依赖 python-docx 的解析逻辑只要文件是合法的 docx就能把资源完整抠出来。2.3 环境准备与最小依赖这个方案对环境的依赖极低Python 3.6 以上即可不需要装 Word也不需要 COM 组件。唯一用到的就是标准库里的zipfile和os如果你还想顺便解析一下图片在文档里的位置可以加装 python-docx但导出这一步完全不需要。# 建议用虚拟环境避免污染全局 python -m venv docx_env source docx_env/bin/activate # Windows 下用 docx_env\Scripts\activate # 核心依赖只有标准库python-docx 是可选的 pip install python-docx这里要说明一下zipfile是 Python 内置的不用 pip 装。我列 python-docx 是因为后面排查图片归属时会用到纯导出的话可以不装。虚拟环境这一步别省我见过有人直接在系统 Python 里跑结果和已有的 docx 库版本冲突报了一堆ImportError排查半天。3. 动手导出图片和嵌入文件的完整脚本3.1 导出所有图片遍历 media 目录先写最核心的图片导出逻辑。思路很简单打开 docx 作为 zip找到所有以word/media/开头的条目逐个读出来写到目标目录。import zipfile import os def export_images(docx_path, output_dir): 从 docx 中导出所有图片 :param docx_path: docx 文件路径 :param output_dir: 图片输出目录 :return: 导出的图片文件名列表 # 确保输出目录存在exist_okTrue 避免重复创建报错 os.makedirs(output_dir, exist_okTrue) exported [] # 以只读方式打开 zipdocx 本质就是 zip with zipfile.ZipFile(docx_path, r) as z: # namelist() 返回压缩包内所有文件路径 for name in z.namelist(): # 只处理 media 目录下的文件其余跳过 if name.startswith(word/media/): # 取原始文件名如 image1.png filename os.path.basename(name) # 跳过目录条目本身有些 zip 会包含目录项 if not filename: continue # 读取二进制数据并写入目标文件 data z.read(name) out_path os.path.join(output_dir, filename) with open(out_path, wb) as f: f.write(data) exported.append(filename) return exported # 调用示例 if __name__ __main__: imgs export_images(report.docx, ./output/images) print(f共导出 {len(imgs)} 张图片) for i in imgs: print(i)逻辑说明zipfile.ZipFile以只读模式打开 docxnamelist()拿到内部所有路径。判断前缀word/media/是过滤关键因为 docx 里还有word/theme/等目录也可能有图片但那些是主题资源不是正文插图。os.path.basename取文件名是为了去掉目录前缀避免写出word/media/image1.png这种嵌套路径。写入用wb二进制模式文本模式会损坏图片。参数说明docx_path传相对或绝对路径都行但路径里如果有中文Windows 下建议用原始字符串rC:\某目录\report.docx否则反斜杠会被当转义符。output_dir会自动创建不用提前手动建。3.2 导出嵌入文件embeddings 目录与扩展名还原嵌入文件的导出逻辑和图片几乎一样但有个坑word/embeddings/下的文件通常叫oleObject1.bin、oleObject2.bin扩展名全是.bin你根本不知道它原本是 Excel 还是 PDF。这时候需要读word/_rels/document.xml.rels这个关系文件里面记录了每个资源的真实类型。import zipfile import os import re def export_embeddings(docx_path, output_dir): 导出嵌入的 OLE 对象并尝试还原真实扩展名 os.makedirs(output_dir, exist_okTrue) exported [] with zipfile.ZipFile(docx_path, r) as z: # 先读关系文件建立 rId 到目标路径的映射 rels_content if word/_rels/document.xml.rels in z.namelist(): rels_content z.read(word/_rels/document.xml.rels).decode(utf-8) # 解析 Relationship 节点提取 Id 和 Target rel_map {} for match in re.finditer(rId([^])[^]*Target([^]), rels_content): rel_map[match.group(1)] match.group(2) for name in z.namelist(): if name.startswith(word/embeddings/): filename os.path.basename(name) if not filename: continue data z.read(name) # 尝试从关系映射里找真实扩展名 real_ext .bin for rid, target in rel_map.items(): if filename in target: # target 形如 embeddings/oleObject1.xlsx if . in target: real_ext . target.rsplit(., 1)[-1] break # 如果原名已有非 bin 扩展名保留 if . in filename and not filename.endswith(.bin): out_name filename else: base filename.rsplit(., 1)[0] out_name base real_ext out_path os.path.join(output_dir, out_name) with open(out_path, wb) as f: f.write(data) exported.append(out_name) return exported逻辑说明关系文件document.xml.rels是 XML 格式每个Relationship节点有Id和Target属性Target指向实际资源路径。用正则提取后建立映射再拿 embeddings 里的文件名去匹配就能还原出.xlsx、.pdf这类真实扩展名。如果匹配不上就保留.bin至少文件内容不丢。参数说明正则里的[^]*是为了跳过中间的其他属性因为 Relationship 节点属性顺序不固定。decode(utf-8)是必须的关系文件是文本不解码会得到 bytes 导致正则匹配失败。3.3 合并成一个可复用脚本把两个函数合到一起加个命令行入口就能当工具用了。import argparse def main(): parser argparse.ArgumentParser(description导出 docx 中的图片和嵌入文件) parser.add_argument(docx, help输入的 docx 文件路径) parser.add_argument(-o, --output, default./docx_output, help输出根目录) args parser.parse_args() img_dir os.path.join(args.output, images) emb_dir os.path.join(args.output, embeddings) imgs export_images(args.docx, img_dir) embs export_embeddings(args.docx, emb_dir) print(f图片导出 {len(imgs)} 个 - {img_dir}) print(f嵌入文件导出 {len(embs)} 个 - {emb_dir}) if __name__ __main__: main()用法就是python export_docx.py report.docx -o ./out。我一般会把输出目录按文档名再分一层避免多个文档混在一起这个可以在调用前自己拼路径。4. 避坑与排查那些让我返工的细节4.1 导出的图片打不开提示文件损坏现象导出的 image1.png 双击打不开或者显示一半就断。原因写入时用了文本模式w而不是wb二进制数据被当字符串处理遇到0x1A之类的字节会被截断。解决所有写文件的地方强制用wb读的时候z.read()返回的就是 bytes不要做任何 decode。4.2 嵌入文件全是 .bin不知道是什么现象导出一堆oleObject1.bin用 Excel 打开提示格式不对。原因没有读关系文件或者关系文件里的 Target 用了相对路径没匹配上。解决先确认word/_rels/document.xml.rels存在再检查正则是否匹配到了Target。有些文档的关系文件里 Target 是embeddings/oleObject1.xlsx直接包含扩展名匹配上就能还原。4.3 图片数量对不上少了浮动图现象文档里明明有 20 张图只导出 15 张。原因用了 python-docx 的inline_shapes浮动图片不在这个集合里。解决回到 zip 层面遍历word/media/这个目录下是所有图片不分内联还是浮动。如果 media 目录下数量也不对那可能是图片以链接方式插入而非嵌入这种情况文件本身就不在 docx 里导不出来。4.4 中文文件名乱码现象导出的文件名变成image1.png没问题但如果是嵌入的中文名附件解出来是乱码。原因zip 内部文件名编码可能是 GBK而 Python 默认按 UTF-8 解码。解决在ZipFile打开时指定metadata_encodinggbkPython 3.11 支持或者用name.encode(cp437).decode(gbk)手动转。我一般先试默认乱码了再加这个参数。4.5 大文档内存爆掉现象处理 500MB 的 docx 时脚本卡死或 MemoryError。原因z.read(name)一次性把整个文件读进内存。解决改用流式读取with z.open(name) as src, open(out_path, wb) as dst: dst.write(src.read())或者用shutil.copyfileobj分块拷贝。对于超大文件分块是必须的。5. 进阶按文档顺序重命名图片并生成一份对照表基础导出只能拿到image1.png这种名字归档时根本不知道哪张图对应文档里哪个位置。我后来加了一步解析document.xml按图片在正文中出现的顺序把 rId 和 media 文件对应起来重命名成fig_001.png、fig_002.png同时生成一个 CSV 对照表记录原始文件名、新文件名和所在段落序号。import zipfile import re import csv import os def export_with_order(docx_path, output_dir): os.makedirs(output_dir, exist_okTrue) with zipfile.ZipFile(docx_path, r) as z: # 读关系文件建立 rId - media 文件名映射 rels z.read(word/_rels/document.xml.rels).decode(utf-8) rid_to_media {} for m in re.finditer(rId(rId\d)[^]*Targetmedia/([^]), rels): rid_to_media[m.group(1)] m.group(2) # 读正文按出现顺序提取 r:embed 的 rId doc_xml z.read(word/document.xml).decode(utf-8) ordered_rids re.findall(rr:embed(rId\d), doc_xml) rows [] seq 1 for rid in ordered_rids: media_name rid_to_media.get(rid) if not media_name: continue src_path fword/media/{media_name} if src_path not in z.namelist(): continue ext os.path.splitext(media_name)[1] new_name ffig_{seq:03d}{ext} data z.read(src_path) with open(os.path.join(output_dir, new_name), wb) as f: f.write(data) rows.append([seq, media_name, new_name, rid]) seq 1 # 写对照表 csv_path os.path.join(output_dir, mapping.csv) with open(csv_path, w, newline, encodingutf-8-sig) as f: writer csv.writer(f) writer.writerow([序号, 原始文件名, 新文件名, 关系ID]) writer.writerows(rows) return rows这段代码的关键在于r:embed的提取顺序。document.xml里图片引用是按正文流出现的re.findall返回的列表就是阅读顺序。rId和 media 文件的映射从关系文件里拿注意 Target 是media/xxx这种相对路径正则里要带上media/前缀。encodingutf-8-sig是为了 Excel 打开 CSV 不乱码这个细节我踩过坑普通 utf-8 在 Windows Excel 里中文会变问号。验证方法很简单打开导出的fig_001.png对照文档第一张图看是否一致再看mapping.csv里的序号是否连续。如果序号跳号说明有图片的 rId 没在关系文件里找到通常是图片被删除但关系残留可以忽略。从那以后我每次做文档归档都强制走一遍“先导出、再对照、后校验”的流程再也没出现过图片对不上号的情况。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

永磁同步电机MTPA/MPTV查表自动生成Python脚本实战指南

永磁同步电机MTPA/MPTV查表自动生成Python脚本实战指南

简介:针对电动汽车永磁同步电机控制中的MTPA(最大转矩电流比)与MPTV(最大功率每伏特)算法,这份资源提供了一套从理论到代码实现的查询表自动生成方案。包含算法详解PDF、MATLAB脚本、GUI界面(fi…

2026/10/18 10:00:37 阅读更多 →
零知识证明如何为链上AI交易代理提供可信执行与可验证推理

零知识证明如何为链上AI交易代理提供可信执行与可验证推理

1. 先聊一个现实问题:链上的交易代理,凭什么让人信任做DeFi的人都清楚,链上环境是一个典型的零信任世界——代码公开、账本公开、人人可校验。但要在这个环境里跑一个AI交易代理,事情就变得拧巴了。假设你在某个协议里部署了一个自…

2026/10/18 10:00:37 阅读更多 →
NLM非局部均值滤波原理与MATLAB图像去噪实现及参数调优

NLM非局部均值滤波原理与MATLAB图像去噪实现及参数调优

简介:非局部均值滤波是图像降噪领域经典算法,这套MATLAB程序包专为学习或实现该算法的开发者与研究生准备,可帮助快速理解原理并完成代码落地。压缩包共十个文件,包含两个程序源文件、七张标准测试图和一个文档说明,整…

2026/10/18 9:59:37 阅读更多 →

最新新闻

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

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

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

2026/10/18 10:46:50 阅读更多 →
用AI Agent聊聊天就能完成数据抓取与报告生成?一文讲透原理与实战

用AI Agent聊聊天就能完成数据抓取与报告生成?一文讲透原理与实战

以前我做数据汇总,流程基本是:先写一个爬虫脚本,跑完看一眼结果,再打开表格工具手动清洗,最后复制粘贴写总结。这套流程干久了你会发现,真正费时间的不是“抓”,而是“改”——页面结构变一下&a…

2026/10/18 10:46:50 阅读更多 →
规格管理工具实测与自建方案:从文档混乱到自动化校验

规格管理工具实测与自建方案:从文档混乱到自动化校验

1. 为什么会盯上规格工具这条赛道先讲个我自己的翻车现场。去年在某团队做一套跨平台业务系统,代码还没写几行,光是对需求就吵了三轮。产品说这个流程要支持灰度开关,开发说设计文档里根本没提这个状态位,测试拿着旧版用例对不上新…

2026/10/18 10:46:50 阅读更多 →
EarlGrey iOS UI自动化测试实战:同步机制、元素匹配与工程接入

EarlGrey iOS UI自动化测试实战:同步机制、元素匹配与工程接入

1. EarlGrey是什么:先搞清楚它解决什么问题做iOS测试的同学应该都有同感:UI自动化这块,选择一直很纠结。Appium、XCUITest、KIF各有一批拥趸,但对原生iOS项目来说,EarlGrey是一个绕不开的名字。它由一家大型科技公司的…

2026/10/18 10:46:50 阅读更多 →
智能UI逆向工程:解构ChatGPT交互状态与行为逻辑

智能UI逆向工程:解构ChatGPT交互状态与行为逻辑

1. 这不是“破解”,而是对智能界面交互逻辑的系统性解构“ChatGPT Intelligent UI 的逆向工程”这个标题,乍看容易让人联想到代码层的暴力拆包或协议嗅探——但实际操作中,我反复验证过:真正有价值的逆向,从来不在二进…

2026/10/18 10:46:50 阅读更多 →
手写现代C++ Web服务器:从socket到HTTP响应的完整闭环

手写现代C++ Web服务器:从socket到HTTP响应的完整闭环

如果你点进这篇文章,多半已经受够了那种“框架搭好、回调填完、项目跑通”的开发方式。业务代码写了好几年,浏览器地址栏敲下回车之后,数据到底在操作系统里经过哪几条路、HTTP 请求是怎么被解析成一个个字段的,大多数人其实说不清…

2026/10/18 10:45: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 阅读更多 →