news 2026/10/23 21:28:13

Python批量处理Word:自动插入图片和表格的办公自动化脚本

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python批量处理Word:自动插入图片和表格的办公自动化脚本

简介:这份资源面向需要批量处理Word文档的Python学习者与办公自动化从业者,聚焦用python-docx库把图片和表格高效写入.docx文件,解决手动逐份编辑重复文档的痛点,属于入门到进阶的实用技能练习。压缩包共12个文件,约367KB,包含10个docx示例文档、1个img_table.py脚本和1张jpg图片,docx用于展示批量生成的工资调整通知效果,py脚本承载核心批量处理逻辑,jpg则作为插入图片的素材,结构紧凑便于直接运行验证。目前已有181人学习下载。读者可从中获得完整的批量插图与建表代码模板,理解Document、add_picture、add_table、cell填充及save等关键用法,并借助os遍历目录的思路,把图片列表与表格数据自动写入多份Word文档,快速迁移到通知、报表等实际办公场景,提升文档处理效率。

1. 批量往 Word 里塞图片和表格,这个脚本把两小时的活压到十秒

上周帮某公司行政整理季度报告,三十多份 Word 文档,每份要插十几张现场照片、再补三张数据表格。手动操作就是打开文档、定位光标、插入图片、调尺寸、画表格、填数据,一套流程下来一份文档至少五分钟,三十份就是两个半小时,中间还容易插错位置。这个python 自动办公- Word_docx_批量把图片和表格写入Word.zip干的就是这件事:用 Python 的python-docx库,把图片和表格按规则批量写进 Word 文档,支持指定插入位置、统一图片尺寸、自动填充表格数据。适合经常跟 Word 打交道的行政、运营、数据分析岗,也适合想拿 Python 做办公自动化的新手练手。它不依赖 Office 软件本身,纯 Python 操作 docx 文件,跑起来不需要装 Word。

2. 环境准备与项目结构:跑通前先看清手里有什么

2.1 依赖安装与版本确认

这个项目核心依赖就一个python-docx,但图片处理那块通常会用到Pillow来读取图片尺寸,方便按比例缩放。我一般会先建虚拟环境,避免跟系统里其他包的版本打架。

# 创建虚拟环境(可选但推荐) python -m venv venv # Windows 激活 venv\Scripts\activate # macOS / Linux 激活 source venv/bin/activate # 安装核心依赖 pip install python-docx Pillow

python-docx负责读写 docx 文件,Pillow负责打开图片获取宽高。装完之后用下面这行验证一下,能打印出版本号就说明环境没问题:

import docx from PIL import Image print(docx.__version__ if hasattr(docx, '__version__') else 'docx ok') print(Image.__version__)

提示:python-docx在 PyPI 上的包名是python-docx,但 import 的时候写import docx,别搞混了。

2.2 目录结构长什么样

解压之后,典型的目录结构大概是这样:

Word_docx_批量把图片和表格写入Word/ ├── main.py # 入口脚本,批量处理逻辑 ├── word_utils.py # 封装好的插入图片、插入表格函数 ├── config.py # 路径配置、图片尺寸、表格样式参数 ├── data/ │ ├── images/ # 待插入的图片,按文档名或序号命名 │ └── tables/ # 表格数据,通常是 csv 或 excel ├── templates/ # 可选的 Word 模板文件 └── output/ # 生成的 Word 文档输出目录

main.py是主流程,遍历数据目录、匹配图片和表格、调用工具函数写入。word_utils.py是核心工具层,把python-docx的 API 封装成insert_image()和insert_table()两个函数。config.py放路径和样式参数,改配置不用动主逻辑。data/images/里的图片命名规则很关键,常见做法是用文档名_序号.jpg或者纯数字序号,脚本按文件名排序后依次插入。

2.3 最小可运行示例

先不跑批量,用一段最小代码验证python-docx能不能正常插图片和表格:

from docx import Document from docx.shared import Inches doc = Document() doc.add_heading('测试文档', level=1) # 插入一张图片,宽度设为 4 英寸 doc.add_picture('data/images/sample.jpg', width=Inches(4)) # 插入一个 3 行 3 列的表格 table = doc.add_table(rows=3, cols=3) table.style = 'Table Grid' for i in range(3): for j in range(3): table.cell(i, j).text = f'单元格 {i}-{j}' doc.save('output/test.docx') print('生成成功')

这段代码跑通,说明环境没问题。add_picture()的width参数控制图片宽度,高度会按比例自动缩放。add_table()创建表格后,用cell(i, j).text填内容,style设置边框样式。如果这里报KeyError找不到样式,说明模板里没有Table Grid,换成'Light Grid Accent 1'或者不设样式也行。

3. 核心模块拆解:图片插入与表格填充的完整链路

3.1 图片批量插入:定位、缩放、命名匹配

批量插图片最容易翻车的地方是尺寸不统一。手机拍的照片动辄 4000 像素宽,直接插进 Word 会撑爆页面。常见做法是先读图片原始尺寸,再按目标宽度算缩放比例。

from docx import Document from docx.shared import Inches from PIL import Image import os def insert_images(doc, image_dir, target_width_inch=4.0): """ 按文件名排序,依次插入图片到文档 :param doc: Document 对象 :param image_dir: 图片目录路径 :param target_width_inch: 目标宽度(英寸) """ # 支持的图片格式 exts = ('.jpg', '.jpeg', '.png', '.bmp') files = sorted([ f for f in os.listdir(image_dir) if f.lower().endswith(exts) ]) for fname in files: fpath = os.path.join(image_dir, fname) # 用 Pillow 读原始尺寸,判断是否需要缩放 with Image.open(fpath) as img: w, h = img.size # 如果原始宽度小于目标宽度,保持原尺寸,避免放大模糊 if w < target_width_inch * 96: doc.add_picture(fpath) else: doc.add_picture(fpath, width=Inches(target_width_inch)) # 图片后加一个空段落,避免两张图挤在一起 doc.add_paragraph()

insert_images()的逻辑分三步:先按扩展名过滤出图片文件并排序,保证插入顺序可控;然后用Pillow读原始宽高,判断是否需要缩放;最后调doc.add_picture()插入,宽度参数只在图片够大时才传。target_width_inch默认 4 英寸,A4 纸正文宽度大约 6 英寸,留点边距刚好。每张图后面加一个空段落,是为了防止连续两张图贴在一起影响排版。

注意:doc.add_picture()的width和height参数如果同时传,图片会被强制拉伸变形。只传width让高度自动算,是更稳妥的做法。

3.2 表格数据填充:从 CSV 到 Word 表格

表格数据一般存在 CSV 或 Excel 里,脚本读出来之后逐行逐列填进 Word 表格。下面这个函数处理 CSV 输入:

import csv from docx import Document def insert_table_from_csv(doc, csv_path, style='Table Grid'): """ 读取 CSV 并插入为 Word 表格 :param doc: Document 对象 :param csv_path: CSV 文件路径 :param style: 表格样式名 """ with open(csv_path, 'r', encoding='utf-8-sig') as f: reader = csv.reader(f) rows = list(reader) if not rows: return n_rows = len(rows) n_cols = max(len(r) for r in rows) table = doc.add_table(rows=n_rows, cols=n_cols) try: table.style = style except KeyError: # 样式不存在时降级为无样式 pass for i, row in enumerate(rows): for j, val in enumerate(row): table.cell(i, j).text = str(val).strip() doc.add_paragraph() # 表格后加空行

encoding='utf-8-sig'是为了兼容 Excel 导出的 CSV 带 BOM 头的情况,不加这个参数第一列标题可能变成\ufeff标题。n_cols取所有行里最长的列数,防止某行列数不一致导致索引越界。table.style用 try-except 包住,是因为不同 Word 模板里可用样式名不一样,找不到就降级处理,不中断流程。

3.3 主流程串联:遍历、匹配、输出

把图片和表格串起来的主流程,核心是「一个数据源对应一份文档」的匹配逻辑:

import os from docx import Document from word_utils import insert_images, insert_table_from_csv def batch_generate(config): """ 批量生成 Word 文档 :param config: 配置字典,含 images_dir, tables_dir, output_dir """ images_root = config['images_dir'] tables_root = config['tables_dir'] output_dir = config['output_dir'] os.makedirs(output_dir, exist_ok=True) # 以图片子目录名作为文档名 for sub in os.listdir(images_root): img_dir = os.path.join(images_root, sub) if not os.path.isdir(img_dir): continue doc = Document() doc.add_heading(sub, level=1) # 插入该文档对应的图片 insert_images(doc, img_dir) # 查找同名 CSV 插入表格 csv_path = os.path.join(tables_root, f'{sub}.csv') if os.path.exists(csv_path): insert_table_from_csv(doc, csv_path) out_path = os.path.join(output_dir, f'{sub}.docx') doc.save(out_path) print(f'已生成: {out_path}')

主流程按images_root下的子目录名来组织文档,每个子目录对应一份 Word。图片从子目录里取,表格找tables_root下同名的 CSV。这种「目录名即文档名」的约定,比在代码里硬编码映射关系灵活得多,加新文档只需要建目录、放图片、放 CSV,不用改代码。os.makedirs(output_dir, exist_ok=True)保证输出目录不存在时自动创建,exist_ok=True避免重复运行时抛异常。

4. 避坑与常见问题:那些让我加班到十点的坑

4.1 图片插入后显示为红叉或空白

现象:生成的 docx 打开后图片位置显示红叉,或者干脆空白。

原因:python-docx插入图片时是把图片二进制嵌入 docx 包里的,如果图片路径含中文或特殊字符,某些版本会读取失败。另外图片本身损坏也会导致这个问题。

解决:图片路径尽量用英文和数字,避免中文目录名。插入前用Pillow打开一次验证图片完整性,打不开就跳过并打印警告。代码里加一层try-except:

try: with Image.open(fpath) as img: img.verify() # 验证图片完整性 except Exception as e: print(f'跳过损坏图片 {fname}: {e}') continue

4.2 表格样式报 KeyError

现象:table.style = 'Table Grid'抛KeyError: "no style with name 'Table Grid'"。

原因:python-docx默认模板里只有部分内置样式,Table Grid在英文模板里叫这个名字,但某些环境或自定义模板里可能没有。

解决:用 try-except 降级,或者先列出所有可用样式再选:

from docx.enum.style import WD_STYLE_TYPE styles = [s.name for s in doc.styles if s.type == WD_STYLE_TYPE.TABLE] print(styles) # 看看有哪些可用

常见可用的有'Table Grid'、'Light Shading Accent 1'、'Light Grid Accent 1'。如果都没有,不设样式也能用,只是没边框。

4.3 批量运行时内存暴涨

现象:处理几十份文档后内存占用越来越高,最后卡死。

原因:Document()对象和Pillow打开的图片没有及时释放,尤其是循环里反复创建 Document 对象。

解决:每处理完一份文档,显式删除 Document 对象并触发垃圾回收:

import gc # 循环末尾 del doc gc.collect()

另外Pillow打开图片用with语句确保关闭。如果图片特别多,可以考虑分批处理,每 10 份文档重启一次脚本。

4.4 插入位置不对,图片跑到表格后面

现象:想先插图片再插表格,结果图片跑到了表格下面。

原因:doc.add_picture()和doc.add_table()都是往文档末尾追加内容,调用顺序决定位置。如果先调了add_table()再调add_picture(),图片自然在表格后面。

解决:严格控制调用顺序,先插图片后插表格。如果需要在表格中间插图片,得用paragraph.insert_paragraph_before()或者操作 XML 元素,复杂度高很多,一般不建议。

4.5 生成的文档打开提示「内容有问题」

现象:Word 打开生成的 docx 时弹窗提示「发现不可读取的内容」。

原因:通常是doc.save()时文件被占用,或者路径不存在导致保存不完整。

解决:保存前确认输出目录存在且有写权限,保存时用绝对路径。如果文件已存在且被 Word 打开,先关闭再运行。加一层保存异常捕获:

try: doc.save(out_path) except PermissionError: print(f'文件被占用,跳过: {out_path}')

5. 二次开发改造:从能跑到好用,我踩过的三个坑

拿到这个脚本之后,直接跑通只是第一步。真正用到实际工作里,我做了三处改造,每一处都对应一个具体的痛点。

第一处是图片命名与排序规则。原始脚本按文件名排序,但手机导出的照片经常是IMG_001.jpg、IMG_002.jpg这种,排序没问题。可一旦混入微信图片_20240101.jpg这种中文名,排序就乱了。我的做法是在config.py里加一个sort_key配置项,支持按文件名、修改时间、或者自定义序号提取函数排序。具体实现是给sorted()传key参数:

import re def extract_number(fname): """从文件名提取数字序号,提取不到返回 0""" match = re.search(r'(\d+)', fname) return int(match.group(1)) if match else 0 files = sorted(file_list, key=extract_number)

这样IMG_001.jpg和微信图片_001.jpg都能按数字正确排序。

第二处是表格数据源从 CSV 扩展到 Excel。CSV 有个硬伤:单元格里不能有换行和逗号,否则解析会错位。实际业务数据经常带这些字符。我加了一个insert_table_from_excel()函数,用openpyxl读 xlsx:

from openpyxl import load_workbook def insert_table_from_excel(doc, xlsx_path, sheet_name=None): wb = load_workbook(xlsx_path, data_only=True) ws = wb[sheet_name] if sheet_name else wb.active rows = list(ws.iter_rows(values_only=True)) # 后续填充逻辑与 CSV 版本一致

data_only=True保证读到的是公式计算后的值,而不是公式本身。这个改动让脚本能直接吃业务部门导出的 Excel 报表,不用先转 CSV。

第三处是模板化输出。原始脚本每次Document()创建的是空白文档,标题样式、页眉页脚、字体都得从头设。我改成从templates/目录加载一个预置模板:

doc = Document('templates/base.docx')

模板里提前设好标题样式、正文字体、页边距,脚本只负责往里填内容。这样生成的文档直接符合公司格式规范,不用再手动调格式。模板文件用 Word 手动建一个,存成 docx 放进去就行,改格式不用动代码。

验证改造是否成功,我一般会跑一个「最小回归集」:准备三份测试数据,分别覆盖「纯图片」「纯表格」「图片+表格混合」三种场景,每次改完代码跑一遍,对比输出文档的图片数量、表格行列数、文件大小是否在预期范围内。这个习惯是从一次惨痛经历来的——有次改排序逻辑,把sorted()的key写错了,导致所有图片顺序颠倒,三十份文档全部重生成。从那以后我每次改完核心逻辑,都强制走一遍最小回归集,确认三种场景都正常再批量跑。希望这个思路帮到你,少加几次班。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/23 21:26:04

从陪读到放手:一个初三家长记录孩子背单词方式的调整过程

去年秋天&#xff0c;一个初三孩子的妈妈跟我聊起她家的晚间日常。孩子英语成绩不算差&#xff0c;但每天背单词的环节总是拖到最晚&#xff0c;书桌前坐半小时&#xff0c;翻来覆去还是那几页。她说得很实在&#xff1a;不是孩子懒&#xff0c;是背了忘、忘了背&#xff0c;看…

作者头像 李华
网站建设 2026/10/23 21:07:20

vtstscripts.tgz:Linux系统级诊断脚本集实战指南

简介&#xff1a;vtstscripts.tgz 是一套面向Linux运维工程师与服务器管理员的轻量级自动化脚本工具集&#xff0c;聚焦系统监控、日志分析、服务管理、备份恢复及安全巡检等高频运维场景&#xff0c;助力中初级运维人员提升日常操作效率与故障响应能力。压缩包共152个文件&…

作者头像 李华
网站建设 2026/10/23 21:06:08

东芝200swin7X64驱动手动安装指南:绿色版驱动包实战与避坑

简介&#xff1a;这份资源是专为东芝200S笔记本在Windows 7 64位系统下准备的驱动合集&#xff0c;面向需要重装系统或修复硬件识别问题的用户&#xff0c;尤其适合习惯手动逐项安装、希望自主掌控驱动版本的中级操作者。压缩包共119个文件&#xff0c;约5.06MB&#xff0c;以d…

作者头像 李华
网站建设 2026/10/23 21:03:29

aos 文件包拆解:CSS3 滚动动画与 IntersectionObserver 实践

简介&#xff1a;这是一份面向前端开发者与网页设计师的 AOS 滚动动画库文件包&#xff0c;基于 JavaScript 与 CSS3 实现&#xff0c;用于为 H5 页面元素添加随滚动触发的动态效果&#xff0c;提升页面互动性与视觉吸引力。包内共 2 个文件&#xff0c;分别为 1 个 css 样式文…

作者头像 李华
网站建设 2026/10/23 21:03:26

VBM与临床量表关联分析:从体素统计到临床解释的完整技术链

1. 这不是“跑个相关系数”那么简单&#xff1a;VBM与临床量表关联分析的真实战场你是不是也见过这样的论文标题&#xff1a;“XX疾病患者灰质体积减少与抑郁评分呈显著负相关&#xff08;r -0.42, p < 0.05&#xff09;”&#xff0c;然后翻到方法部分&#xff0c;只看到一…

作者头像 李华
网站建设 2026/10/23 21:01:07

大模型能不能一边思考一边听你说话?

你有没有想过&#xff0c;为什么和Siri或者Alexa聊天的时候&#xff0c;总感觉在跟一个反应迟钝的人打交道&#xff1f;你说完一句话&#xff0c;它要停顿一下才开始处理&#xff0c;处理完了才能回应&#xff0c;如果你中途想插一句话打断它&#xff0c;系统往往要愣一下才能反…

作者头像 李华