行业资讯
📅 2026/9/8 22:52:55
Python自动化:用python-docx批量将图片和表格写入Word
简介面向Python办公自动化初学者这份压缩包提供了一套可运行的图片与表格批量写入Word文档的完整方案。包内共12个文件以10份docx演示文档、1份Python脚本和1张示例图片为主脚本完整演示了使用python-docx库遍历图片文件夹、创建表格并填充数据、最终保存文档的流程10份docx文档则对应脚本在不同员工数据下生成的工资调整通知样例方便读者逐份对照检查输出效果。压缩包仅367KB轻量易用无需额外安装复杂依赖适合本地快速测试。目前已有179人学习下载反馈实用。通过阅读脚本和对照生成的Word文档读者可以掌握Document、add_picture、add_table、cell等核心API的用法理解如何遍历文件夹中的图片、如何动态构造表格行与列并将这套批量处理方法迁移到工资调整通知、产品图录、数据报告等真实办公场景显著提升文档自动化处理效率。 写 Python 自动化办公脚本的人十有八九都躲不过 Word 文档处理。把图片一张张手动拖进 Word再逐个排版表格短文档还能忍一旦涉及到几十页的报告、产品说明或者数据汇总人肉操作不仅是浪费时间还特别容易出错。去年我做一个批量设备巡检报告生成任务时就靠 python-docx 把三百多张现场照片和对应的测试数据表格在几分钟内全部写进了几十份 Word 文档里。今天这篇就围绕“Word_docx_批量把图片和表格写入 Word”这个场景把整个实现思路、关键代码、以及那些只有真跑过才会踩到的坑一次说清楚。这个项目适合谁只要你日常需要和 Word 打交道且工作里存在“重复性地把图片、表格填进文档”这种操作那这篇文章就能给你省下大把时间。不需要你有很深的技术底子有基础的 Python 语法概念能跑脚本就够了。1. 项目定位先搞清楚这个脚本到底要解决什么问题这个项目的核心任务其实非常聚焦用 Python 的 python-docx 库批量创建或修改 Word 文档然后把图片和表格按指定规则写入指定位置。听起来简单但真正操作起来你会发现里面藏了不少“小九九”。1.1 为什么要用 python-docx 而不是其他方案很多人第一时间会想到 win32com甚至有人会用 Docx4j 或者 pandoc。我个人的经验是纯 Python 环境、跨平台场景、不依赖 Office 安装的脚本首选就是 python-docx。python-docx 处理的是 Word 的底层 XML 结构它不需要你机器上装着 Microsoft Word。这一点在服务器上跑自动化任务时是绝对的硬优势。win32com 虽然能调用 Word 的完整能力但你必须装 Office而且在 Linux 环境下基本玩不转。相比之下python-docx 就是一个纯粹的库pip 装完就能用对部署环境极其友好。另外从文档结构角度看python-docx 的操作模型和 Word 的文档模型是高度对应的Document文档包含多个 Paragraph段落和 Table表格图片本质上是以 InlineShape 形式嵌入到 Paragraph 里的 Run 里。对这个模型有个基本认知后边写代码就不会觉得 API 很玄。1.2 批量需求里最常见的三种典型场景根据热搜词和实际生产中遇到的需求我归纳了这么几类你们可以对号入座批量生成报告类文档比如巡检报告、检测报告、项目验收文档。这类文档的特点是文档骨架固定每份文档里嵌入不同的现场图片和对应的结果数据表格。批量整理资料类文档比如把一批产品照片、参数说明表、技术指标表自动汇总到一份 Word 文件里。批量格式化文档比如把 Excel 里存放的数据自动转成 Word 里规范化的表格同时插入相关的截图或示意图。这个项目脚本的设计思路需要天然兼容这几类场景。核心就是提供一份“数据清单”可以是文件夹下的图片也可以是 Excel 里的数据然后脚本按规则把这些素材塞进 Word 模板。2. 环境准备与依赖细节别在起步阶段就翻车python-docx 的安装本身没有任何难度一条 pip 命令就搞定。但我在实际指导别人跑项目时发现至少有 30% 的报错都发生在环境准备阶段而且报错信息特别有迷惑性。2.1 安装命令与虚拟环境建议pip install python-docx对了这里要强调一点这个库的导入名和 pip 包名不一致。Python 里 import 的时候用的是docx但 pip 安装时是python-docx。如果你错误地执行了pip install docx你装的其实是另一个完全不相关的旧库代码运行时会直接报模块属性错误。这是新手最容易犯的错没有之一。有条件的话建议用虚拟环境管理项目依赖。我之前在服务器上跑脚本一开始直接用全局 Python 环境装了一堆包后来因为其他项目升级了某些依赖导致这个脚本里 docx 库的行为出现了微妙的变化排查了很久才发现是依赖冲突。用 venv 隔离是最稳的做法python -m venv office_env source office_env/bin/activate # Windows 下是 office_env\Scripts\activate pip install python-docx2.2 版本选择与兼容性问题python-docx 当前的稳定版本在 1.1.xAPI 相对稳定。不过有一点要注意如果你是从老项目迁移过来的某些旧写法在新版本里可能被标记为废弃。比如直接操作document.add_paragraph(styleNormal)这种写法虽然还能用但更规范的方式是先获取样式对象再应用。这些细节不影响核心功能但会在你复制网上旧代码的时候突然给你冒一个 warning。另外图片格式支持方面python-docx 底层依赖 Pillow 库来处理图片尺寸等信息。所以如果你打算插入 JPEG、PNG 之外的格式尤其是 WebP 这种新格式时建议保证 Pillow 是较新版本。我遇到过一次插入 WebP 图片直接报UnrecognizedImageError升级 Pillow 后就正常了。3. 图片批量写入 Word核心逻辑与尺寸控制图片写入是第一个重头戏。python-docx 里插入图片的 API 看起来很简单就是document.add_picture(path)但实际使用中要控制的事情远比表面上多。3.1 add_picture 的底层逻辑与常用参数add_picture()方法可以接收图片文件路径或者文件流它会创建一个新的段落并把图片作为一个内嵌图形放进该段落。它的核心参数width图片宽度可以传Inches(6)、Cm(15)等单位对象height图片高度不传则按比例自动缩放这里有个非常重要的细节当你只指定高度或只指定宽度时python-docx 会按图片原始宽高比自动计算另一边。但如果你同时指定宽高而宽高比和原始图片不一致图片就会被拉伸变形。我在做批量生成时从来不会同时传两个参数而是固定宽度让高度自适应。看一个实际例子把文件夹里所有 JPG 图片按固定宽度插入文档from docx import Document from docx.shared import Inches import os doc Document() image_folder ./images for img_name in os.listdir(image_folder): if img_name.lower().endswith((.jpg, .jpeg, .png)): img_path os.path.join(image_folder, img_name) doc.add_picture(img_path, widthInches(5.5)) # 最后一张图不需要额外空行但前面的加一个空段落视觉上更自然 doc.add_paragraph() doc.save(图片汇总.docx)这段代码核心逻辑就两件事遍历文件夹按图片大小统一宽度插入。你有没有想过为什么要统一宽度因为如果图片来源不同手机拍的、相机拍的、截图原始尺寸差异巨大。不限制宽度的话有的图在页面上大得离谱有的小到看不清生成的文档根本没法看。3.2 控制图片位置和对齐方式的正确姿势add_picture()默认生成的段落是左对齐的这在很多报告场景里并不好看。改对齐方式有一个很多人不知道的细节add_picture()方法本身没有对齐参数你需要自己获取它所在的那个段落然后单独设置对齐方式。from docx.enum.text import WD_ALIGN_PARAGRAPH # 插入图片时add_picture 会返回 InlineShape而不是 Paragraph # 所以要先把图片段落“找出来” doc.add_picture(img_path, widthInches(5.5)) # 新插入的图片在文档最后一个段落我们取最后一段来设置格式 last_paragraph doc.paragraphs[-1] last_paragraph.alignment WD_ALIGN_PARAGRAPH.CENTER这个方法在实际使用中非常顺手。另外如果需要在图片下面加图注比如“图1-设备外观.jpg”只需要再加一个段落设置为居中字号调成小五或者 9pt 即可这样整个图片区就规范化了。3.3 批量插入技术细节图片目录排序与异常处理批量插入时有个细节容易被忽略os.listdir()返回的文件名顺序不是按数字大小排的而是按字符串排序。你明明有 1.jpg 到 20.jpg插入顺序却是 1.jpg, 10.jpg, 11.jpg, 2.jpg……因为字符串比较时 “10” 排在 “2” 前面。解决方式是用自然排序import re def natural_sort_key(s): return [int(text) if text.isdigit() else text.lower() for text in re.split(r(\d), s)] image_files sorted(os.listdir(image_folder), keynatural_sort_key)还有就是要处理损坏图片或格式不支持的图片。我建议把单张图片的插入操作包在 try-except 里这样一张图出错不会中断整个批量任务for img_name in image_files: img_path os.path.join(image_folder, img_name) try: doc.add_picture(img_path, widthInches(5.5)) except Exception as e: print(f图片 {img_name} 插入失败: {e}) continue这样做的好处显而易见跑批量的任务时最怕的就是中途挂掉日志输出能帮你快速定位哪张图有问题而不是抓瞎。4. 表格批量写入 Word从数据到结构化呈现表格部分是这个项目的另一个核心。python-docx 操作表格的 API 和图片相比稍微绕一点但掌握规律之后就非常顺手。4.1 add_table 创建表格与行列填充逻辑doc.add_table(rows, cols)可以创建一个空表格。但这里有一个使用上的关键点创建出来的表格默认没有样式在 Word 里显示的就是一个简简单单的网格。网络上的教程里90% 的案例都会给表格指定一个内置样式from docx.util import Inches table doc.add_table(rows5, cols3) table.style Table GridTable Grid是 Word 内置样式会给表格加上黑色的全边框。如果不设置这个样式在页面上看会像一段没有边框的文字矩阵尤其是打印或者转 PDF 的时候会非常奇怪。填充单元格数据的时候核心操作是通过table.cell(row_index, col_index).text value来给指定单元格赋值。但要注意cell 的text属性每次赋值都会清空该单元格原来的内容如果你需要在一个单元格里加多段内容或者带格式的内容就得用paragraphs来操作了。4.2 一个完整的批量表格写入示例假设我们要把几组测试数据写入一个汇总表格每组数据有编号、项目名称、结果、备注四列from docx import Document doc Document() doc.add_heading(测试数据汇总表, level1) data [ [001, 外观检查, 通过, 无明显划痕], [002, 尺寸测量, 通过, 公差范围内], [003, 电气性能, 不通过, 耐压异常需复测], [004, 包装检查, 通过, 完好], ] table doc.add_table(rows1, cols4) table.style Table Grid # 写入表头 hdr_cells table.rows[0].cells hdr_cells[0].text 编号 hdr_cells[1].text 项目名称 hdr_cells[2].text 结果 hdr_cells[3].text 备注 # 写入数据行 for record in data: row_cells table.add_row().cells row_cells[0].text record[0] row_cells[1].text record[1] row_cells[2].text record[2] row_cells[3].text record[3] doc.save(表格示例.docx)这个示例里有一个 API 的重要用法table.add_row()是动态添加行的方法它在表格已有的行数基础上追加新行并且返回新行的 Cells 集合。这个方法比创建表格时一次性指定 rows 再逐行写数据更灵活因为你不用提前知道数据量是多少循环往里面加就行。4.3 设置表格列宽和单元格内容格式的实际操作有热搜词提到了“poi 设置 word 表格单元格宽度”说明很多人都在为表格宽度发愁。python-docx 里设置列宽的操作比较容易踩坑直接设置table.columns[i].width有时候会不起作用。正确的做法是同时设置表格的autofit属性以及逐列设置宽度。我总结的稳定写法是这样的from docx.shared import Cm table.autofit False col_widths [Cm(2), Cm(3), Cm(2.5), Cm(5)] for idx, width in enumerate(col_widths): table.columns[idx].width width关于autofit这行浅析表格默认处于自动调整列宽的状态Word 会根据内容长短动态分配列宽。如果你强行指定了宽度但 autofit 还是开启的最终效果就是你在 Python 里设的数字被 Word 无视。所以先关掉自动调整再设宽度才有效。对于单元格内容的格式比如想让表头加粗并居中可以操作单元格里的段落from docx.enum.text import WD_ALIGN_PARAGRAPH for cell in table.rows[0].cells: for paragraph in cell.paragraphs: paragraph.alignment WD_ALIGN_PARAGRAPH.CENTER for run in paragraph.runs: run.bold True不过这里有个细节cell.text value赋值后单元格里默认会有一个 Run你要给这个 Run 设置粗体得先访问到这个 Run。如果你在赋值设置粗体时发现没有生效很有可能是你在设置 text 之前就去访问 runs此时 run 列表还是空的。正确顺序是先赋值再取 paragraph.runs[0] 改格式。5. 批量执行的完整流程循环结构、素材管理与文档命名前面把图片和表格分开讲了接下来要把它们整合进一个批量流程里。这一段是“批量化”三个字真正意义上的落地环节。5.1 配置化的批量处理模式数据清单驱动在真实的自动化项目里图片和表格往往不是独立插入的而是有对应关系的某一张产品照片对应某一组检测数据共同组成一份报告的一个章节。这种关系最好通过“数据清单”来驱动而不是让脚本自己盲目地遍历文件夹。我常用的做法是维护一个 JSON 配置文件或者直接读 Excel 清单。展示一下 JSON 配置的模式[ { product_id: P-001, photo: images/P-001.jpg, metrics: [ {item: 重量, value: 12.3kg, result: PASS}, {item: 尺寸, value: 30x20x10cm, result: PASS} ] }, { product_id: P-002, photo: images/P-002.jpg, metrics: [ {item: 重量, value: 13.1kg, result: FAIL} ] } ]有了这个清单脚本的逻辑就变得非常干净加载清单遍历每一项写入一个标题段落插入对应图片再创建表格填入指标数据最后保存文档。5.2 每个数据项生成一份文档的主循环为了通用起见我给这个项目设计了主循环代码核心思路是“一个产品项生成一份独立的 Word 文档”import json from docx import Document from docx.shared import Inches, Cm from docx.enum.text import WD_ALIGN_PARAGRAPH with open(config.json, r, encodingutf-8) as f: items json.load(f) for item in items: doc Document() # 标题 doc.add_heading(f产品报告 - {item[product_id]}, level1) # 写入图片 doc.add_picture(item[photo], widthInches(5)) doc.paragraphs[-1].alignment WD_ALIGN_PARAGRAPH.CENTER doc.add_paragraph(f图{item[product_id]} 实物照片).alignment WD_ALIGN_PARAGRAPH.CENTER # 写入表格 table doc.add_table(rows1, cols3) table.style Table Grid hdr table.rows[0].cells hdr[0].text 检测项目 hdr[1].text 测量值 hdr[2].text 判定结果 for row_data in item[metrics]: row_cells table.add_row().cells row_cells[0].text row_data[item] row_cells[1].text row_data[value] row_cells[2].text row_data[result] doc.save(f./output/{item[product_id]}_报告.docx) print(f已生成: {item[product_id]}_报告.docx)这种文档组织方式的妙处在于你新增一项产品只需要在 JSON 里加一个对象脚本代码一行都不用改。把数据从代码中抽离出来是可维护性的第一大胜利。5.3 输出目录管理与文档重名冲突处理批量生成时输出目录管理也是一个容易出问题的地方。如果生成的文件和之前的旧文件重名Windows 系统下 docx 文件会直接弹“文件已存在”的覆盖提示不会Python 的 open 操作会直接覆盖写入旧文件内容就没了。有时候这恰恰是我们的目标比如重新生成最新版报告但有时候却是灾难。我习惯在代码最开始就把输出目录处理好并且给文件名加上时间戳import os from datetime import datetime os.makedirs(./output, exist_okTrue) timestamp datetime.now().strftime(%Y%m%d_%H%M%S) filename f{item[product_id]}_报告_{timestamp}.docx但是也要提醒一下如果只需要最新一份报告加时间戳反而会增加文件管理负担。这种情况下可以先删除旧的特定前缀文件再生成新的。这个策略没有绝对的对错想清楚你的使用场景再决定。6. 实测中遇到的坑与规避思路想少加班就认真看这段这个项目算不上复杂但坑真不少。我把实际踩过的坑集中在这部分每一个都是在真实生产环境中炸过的雷。6.1 图片插入后文档体积急剧膨胀的问题这个问题最隐蔽。当你往文档里插入 20 张 5MB 的 JPEG 图片后生成的 docx 文件可能高达 100MB 以上。很多人以为这是正常的其实不是。docx 本质是一个 zip 压缩包python-docx 在插入图片时会把原图数据完整地存进去不会对图片做任何压缩或尺寸优化。解决方案分两种第一种在代码里压缩图片用 Pillow 先统一把图片处理成宽度不超过 1200 像素、质量 80 的 JPEG再插入文档。这个方法对控制体积最有效。第二种直接限制文件大小如果原始图片本来就网络上传的截图体积不大可以不处理。但如果是相机原图强烈建议先做预处理。一个小循环示例把目录下的图片统一压缩到目标文件夹from PIL import Image import os src_dir ./raw_images dst_dir ./compressed_images os.makedirs(dst_dir, exist_okTrue) for img_name in os.listdir(src_dir): if not img_name.lower().endswith((.jpg, .jpeg)): continue img Image.open(os.path.join(src_dir, img_name)) img.thumbnail((1200, 1200)) img.save(os.path.join(dst_dir, img_name), quality85, optimizeTrue)6.2 表格列宽设置后显示不变的原因与对策前面提到了autofit的问题但还有一种情况是你在 Python 里设置了列宽用 LibreOffice 打开看是变了但用 Microsoft Word 打开显示还是原来的宽度。这个问题的根源是表格 XML 里的tblLayout设置。python-docx 默认生成的表格布局是 autofit 类型你在 Word 里看到的行为受这个设置控制。解决方式是手动修改表格的 layoutfrom docx.oxml.ns import qn from docx.oxml import OxmlElement tbl table._tbl tblPr tbl.tblPr if tbl.tblPr is not None else OxmlElement(w:tblPr) layout OxmlElement(w:tblLayout) layout.set(qn(w:type), fixed) tblPr.append(layout)这段代码做的事情是把表格布局从自动调整切换为固定布局。设置完成后你之前指定的列宽就能稳定生效了不管哪种 Office 软件打开都会保持一致。6.3 文档中插入大量图片后内存占用飙升的应对方案如果是超大文档比如把 1000 张图片插入一个 Word 里你会发现脚本运行到后面越来越慢最终可能内存耗尽。原因很简单Document 对象把所有图片和 XML 结构都放在内存里最后 save 时才一次性写入磁盘。处理方式是在逻辑允许的情况下分多个文档保存每个文档控制图片数量。如果确实需要一个包含大量图片的单个文档建议考虑更底层的操作方式——直接修改 docx 的 zip 结构但那已经是另一个维度的工程了日常办公场景按照分文档处理即可。7. 项目扩展方向这个脚本可以怎么演进出更多价值把这个批量写入脚本跑通之后它就有了一次“进阶”的可能。这里分享几个我在实际工作中拓展出的常见方向。7.1 搭配 Excel 数据源实现表格全自动生成之前我们使用 JSON 作为数据源对于非技术同事来说维护成本还是有点高。他们最熟悉的工具是 Excel。用 pandas 或 openpyxl 读取 Excel 中的数据再填入 Word 表格整个自动化对业务人员来说就完全透明了。尤其是那些每天都要更新数据表格、每周要出周报的场景一个人一周能省下大半天的时间。7.2 与飞书机器人结合实现任务触达热门搜索中有一条“飞书机器人发送表格”说明现在很多人希望把办公自动化和协同办公工具打通。比如在服务器上跑一个数据采集程序自动把日报数据写入 Word 或者发送到飞书群。这个扩展方向不复杂难点只在于 Webhook 的调试和消息格式的适配但一旦打通工作流的自动化程度会上升一个量级。7.3 批量修改已有 Word 模板如果业务要求的是“在指定位置插入图片”而不是“从零生成新文档”这时候需要使用到模板技术。方法是在 Word 里预先用书签Bookmark标记插入位置然后通过 python-docx 的document.paragraphs遍历找到书签所在段落在它后面插入图片。这个方法我之前在自动生成合同场景中用过效果非常好比从零建文档省事得多。批量把图片和表格写入 Word 这个项目本质上是在解决“从数据素材到结构化文档”的重复劳动问题。从环境准备、图片尺寸控制、表格列宽设置到批量任务架构和实战避坑每一环都有可优化的细节。我建议你拿到代码后先拿三五张图片、十几行数据试跑把流程跑通再逐步应用到大文件量的真实业务里。等这个脚本真正在你的工作流里跑起来的时候你就会发现以前两个小时的工作现在只需要喝杯咖啡的时间。本文还有配套的精品资源点击获取