简介这份资源面向需要批量处理Word文档的Python学习者与办公自动化从业者聚焦用python-docx库把图片和表格高效写入.docx文件解决重复手工排版、逐份生成通知类文档的痛点属于入门到进阶的实用技能练习。压缩包共12个文件以10个docx成品文档为主体直观展示批量生成后的效果另含1个py脚本作为核心实现以及1张jpg图片用于插入演示整体约367KB轻量易取。已有181人学习下载说明该场景在自动化办公中需求稳定。读者可拿到可直接运行的批量处理脚本理解Document创建、add_picture插图、add_table建表与cell填充、doc.save保存的完整链路并借助os遍历目录的思路扩展到自有图片与表格数据快速套用到工资调整通知等重复文档的批量生成任务中。1. 批量往 Word 里塞图片和表格这个脚本把重复劳动干成了流水线如果你做过标书、检测报告、巡检记录这类文档一定懂那种痛几十份 Word每份都要插十几张现场照片再配一张参数表格图片还得统一尺寸、表格还得对齐表头。手动干一下午眼睛花、手腕酸最后还容易漏插一张图。这个python 自动办公- Word_docx_批量把图片和表格写入Word.zip就是冲着这个场景来的——它用python-docx把「图片批量插入」和「表格批量写入」两件事封装成可复用的脚本你只要准备好图片文件夹和一份数据源剩下的排版、命名、保存全交给代码。适合经常处理批量文档的行政、测试、项目助理也适合想拿它当python-docx入门练手项目的开发者。下面我按「能干什么 → 怎么跑 → 怎么改」的顺序把这个包拆开讲一遍。2. 项目结构与技术选型为什么是 python-docx 而不是 COM 调用2.1 目录长什么样每个文件负责哪一段拿到压缩包解压后目录结构通常不会太复杂常见做法是分成「入口脚本 配置 素材 输出」四块。我按这个项目场景下最合理的组织方式给你还原一下word_batch_tool/ ├── main.py # 入口串联读取图片、读表格数据、写入 Word ├── config.py # 路径、图片宽度、表格样式等参数集中管理 ├── utils/ │ ├── image_helper.py # 图片尺寸处理、格式校验 │ └── table_helper.py # 表格数据解析、表头生成 ├── data/ │ ├── images/ # 待插入的图片按编号命名 │ └── records.xlsx # 表格数据源一行一条记录 ├── templates/ │ └── base.docx # 可选带页眉页脚的空白模板 └── output/ # 生成的 Word 文件落在这里这个划分的好处是main.py只负责流程编排具体「图片怎么缩放」「表格怎么建」都下沉到utils。你后面要改图片宽度只动config.py要换表格样式只动table_helper.py不会牵一发动全身。data/images里的图片建议用001.jpg、002.jpg这种带序号的名字脚本按序号排序后依次插入顺序可控。2.2 技术选型python-docx 的定位核心依赖就一个python-docx。它直接操作.docx的 XML 结构不依赖本机装没装 Office跨平台跑得通服务器上也能用。相比之下用win32com调 Word COM 接口虽然能复用 Office 的排版能力但要求机器必须装 Word、只能跑在 Windows 上批量任务里还容易因为 Word 进程没退出而卡死——这是很多人踩过的坑。所以这个项目选python-docx是合理的轻、稳、可移植。安装就一行pip install python-docx openpyxlopenpyxl是用来读records.xlsx的如果你表格数据源是 CSV那用标准库csv就够了可以不装。这里提一句版本python-docx在 0.8.11 之后 API 基本稳定add_picture、add_table、add_paragraph这几个方法你照着用不会有大出入。2.3 整体数据流一条记录对应一份文档脚本的主流程是「外层循环文档、内层循环图片和表格行」。常见做法是读records.xlsx每一行代表一份要生成的文档同时读images目录按命名规则把图片分组每组对应一份文档。两份数据靠一个共同字段比如「编号」或「项目名」关联起来。这样你新增一份文档只要在 Excel 加一行、在 images 下建一个同名子文件夹脚本自动识别不用改代码。这个「数据驱动」的思路是批量办公脚本的灵魂后面二次开发也围绕它展开。3. 核心模块拆解图片插入、表格生成、文档保存三段链路3.1 图片批量插入尺寸、对齐、顺序三件事先看图片插入这段。python-docx的add_picture如果不传宽高会按图片原始尺寸插入手机拍的照片动辄 4000 像素宽塞进 A4 页面直接溢出。所以必须显式控制宽度。下面是我一般会写的封装from docx import Document from docx.shared import Cm from docx.enum.text import WD_ALIGN_PARAGRAPH import os def insert_images(doc, image_paths, width_cm10): 把一组图片依次插入文档统一宽度并居中 for img_path in image_paths: # 校验文件存在避免路径写错时静默跳过 if not os.path.exists(img_path): print(f[跳过] 图片不存在: {img_path}) continue # 新建段落用于承载图片方便单独设置对齐 para doc.add_paragraph() para.alignment WD_ALIGN_PARAGRAPH.CENTER run para.add_run() # 只传宽度高度按原始比例自动缩放避免图片变形 run.add_picture(img_path, widthCm(width_cm))逻辑说明add_picture挂在run上而不是直接挂document是为了能控制图片所在段落的对齐方式。只传width不传heightpython-docx会按原始宽高比自动算高度这是防止图片被拉变形的关键。参数width_cm默认 10 厘米A4 正文宽度约 16 厘米10 厘米居中放视觉上比较舒服如果你要一页放两张并排可以改成 7 厘米左右再配合表格布局。顺序问题os.listdir返回的顺序在不同系统上不保证一致所以取到文件列表后一定要sorted()。如果文件名是1.jpg、2.jpg、10.jpg字符串排序会把10排到2前面这时候要么用零填充命名01.jpg要么在排序时提取数字做 key。这个细节不注意生成的文档图片顺序就是乱的属于典型的「玄学 bug」。3.2 表格批量写入表头、数据行、样式一次说清表格部分python-docx的add_table(rows, cols)建的是空表需要自己填单元格。下面这段把「表头 数据行」一起处理from docx.shared import Pt def insert_table(doc, headers, rows, styleTable Grid): 插入带表头和数据行的表格 headers: 表头文字列表如 [编号, 名称, 数值] rows: 二维列表每个子列表是一行数据 table doc.add_table(rows1, colslen(headers)) table.style style # Table Grid 自带边框最常用 # 填表头 hdr_cells table.rows[0].cells for i, text in enumerate(headers): hdr_cells[i].text str(text) # 表头加粗字号 10.5五号 for para in hdr_cells[i].paragraphs: for run in para.runs: run.font.bold True run.font.size Pt(10.5) # 填数据行 for row_data in rows: cells table.add_row().cells for i, val in enumerate(row_data): cells[i].text str(val)逻辑说明rows1是先建一行占位当表头数据行用add_row()动态追加这样不用提前算总行数。styleTable Grid是python-docx内置样式里唯一稳定带全边框的其他样式在不同 Word 版本里渲染效果不一致建议就用它。表头加粗那段要遍历paragraphs再遍历runs因为单元格文字默认会生成一个 run直接设cell.text后拿不到 run 引用得从段落里取。参数上headers和每行row_data的长度必须一致否则cells[i]会越界报IndexError。稳妥做法是在函数开头加一句assert all(len(r) len(headers) for r in rows)把错误提前暴露而不是写到一半崩掉。3.3 文档保存与批量循环路径拼接别用字符串加号把图片和表格串起来主循环大概长这样import os from docx import Document from openpyxl import load_workbook def build_documents(config): wb load_workbook(config[excel_path]) ws wb.active headers [c.value for c in ws[1]] # 第一行当表头 for row in ws.iter_rows(min_row2, values_onlyTrue): doc Document() # 或 Document(config[template_path]) 用模板 doc.add_heading(f报告编号{row[0]}, level1) # 按编号找对应图片文件夹 img_dir os.path.join(config[image_root], str(row[0])) if os.path.isdir(img_dir): imgs sorted( os.path.join(img_dir, f) for f in os.listdir(img_dir) if f.lower().endswith((.jpg, .png, .jpeg)) ) insert_images(doc, imgs, width_cmconfig[img_width]) # 插入该行对应的表格数据这里简化为单行 insert_table(doc, headers, [list(row)]) out_path os.path.join(config[output_dir], f{row[0]}.docx) doc.save(out_path) print(f[生成] {out_path})逻辑说明iter_rows(min_row2, values_onlyTrue)跳过表头直接拿数据值比按单元格坐标取值清爽。图片目录用os.path.join拼接不要用config[image_root] / str(row[0])后者在 Windows 上混用斜杠容易出问题。doc.save之前所有内容都已写入内存中的文档对象保存即落盘。参数说明config字典集中放excel_path、image_root、output_dir、img_width、template_path五个键改路径不用翻代码。template_path如果传了Document(template_path)会基于模板创建页眉页脚、样式都继承过来这是做正式报告时最省事的做法。4. 避坑与常见问题图片不显示、表格错位、进程卡死4.1 图片插进去是红叉或空白现象生成的 Word 打开后图片位置显示红叉或空白框。原因通常是图片路径含中文或空格python-docx在部分环境下对非 ASCII 路径处理不稳也可能是图片本身损坏。解决把图片目录改成纯英文路径或在读图前用PIL打开验证一次确认图片是jpg/png而非webppython-docx不认 webp。4.2 表格列宽忽宽忽窄中文挤成竖排现象表格某些列特别窄中文一个字一行。原因python-docx默认按内容自动分配列宽长文本列会挤压其他列。解决建表后手动设列宽for col in table.columns: col.width Cm(3)或者给单元格设cell.width。注意列宽设置要在填完数据之后做否则会被后续写入覆盖。4.3 批量跑几百份时内存涨、最后崩掉现象循环到一两百份时程序变慢甚至MemoryError。原因每轮Document()对象没被释放Python 垃圾回收没及时跟上。解决把单份文档的生成逻辑抽成独立函数函数返回后对象自然出作用域或者在循环末尾显式del doc。更稳的做法是分批处理每 50 份gc.collect()一次。4.4 用模板时样式丢失现象基于template.docx生成但标题字体、页眉全没了。原因Document(template_path)只继承模板的样式定义和节属性如果你在代码里用add_heading但模板里没定义对应 Heading 样式就会回退到默认。解决先在模板里把 Heading 1/2、正文样式调好代码里只用模板已有的样式名或者干脆不用模板全部用代码设字体字号。4.5 文件名重复导致覆盖现象输出目录里文件数比预期少。原因Excel 里编号列有重复值{row[0]}.docx同名互相覆盖。解决保存前判断os.path.exists存在就加时间戳后缀或者在 Excel 侧先做唯一性校验把重复编号揪出来。5. 二次开发把单机脚本改成可配置、可扩展的小工具5.1 配置外置从改代码到改配置文件现在参数都写在config.py里改一次要动代码。更实用的做法是抽成config.yaml或config.json用pyyaml/ 标准库json读进来。这样非开发同事也能改图片宽度、输出目录不用碰 Python。我一般会加一层默认值合并读到的配置覆盖默认字典缺的键用默认值补避免配置文件少写一项就报KeyError。5.2 图片布局升级一页多图与图注当前是每张图一个段落、垂直排列。如果你要做「一页两张并排」可以用一个 1 行 2 列的表格来装图片把图片塞进单元格表格边框设成无。图注也好加在图片段落后面add_paragraph(图1 现场照片)设成居中小字号。这个改造点很实用检测报告里几乎都要图注。5.3 表格数据源扩展从单行到多行分组现在每份文档只插一行表格数据。如果一份报告要插多行比如一个项目的多条检测记录可以把 Excel 按编号分组用itertools.groupby或先建一个dict按编号聚合再在循环里取对应的一组行传给insert_table。改动量不大但适用场景一下宽了很多。5.4 验证方法别只看「跑完了」批量脚本最怕「跑完了但结果是错的」。我的习惯是加一个自检步骤生成后遍历输出目录用python-docx重新打开每份文档统计len(doc.inline_shapes)图片数和len(doc.tables)表格数跟预期值比对不一致就打印文件名。这一步能抓住「图片路径错导致静默跳过」这类问题——脚本不报错但文档里少图人工抽查很难发现。5.5 一个具体技巧用命名规则驱动一切最后说个我踩过坑才养成的习惯让文件名和文件夹名承担「配置」职责。图片文件夹用编号命名图片用序号命名Excel 第一列也是编号三者对齐后脚本不需要任何额外的映射表新增数据零改动。早期我图省事用中文项目名做文件夹结果遇到特殊字符、空格、大小写不一致排查了一下午。从那以后我每次做批量文档脚本都强制走一遍「编号对齐 路径纯英文 生成后自检」这三步基本没再翻过车。希望这个拆解帮到你拿到包先跑通单份再放量批处理稳。本文还有配套的精品资源点击获取