资讯动态

Python自动化:批量生成带图片和表格的Word并打包zip

发布时间:2026/9/8 23:01:12 来源:尧图企业网站定制
简介这是一份面向Python办公自动化入门者的实操教程包聚焦使用python-docx库批量操作Word文档解决大批量文档中重复插入图片、生成表格的痛点。压缩包共12个文件包含1个可直接运行的img_table.py脚本、10份docx格式的工资调整通知示例文档及1张jpg图片整体仅367KB结构精炼便于快速上手。已有179人浏览学习。包内docx文件展示了不同员工的工资调整通知可作为输出效果参考脚本具备通用性稍改图片目录与表格数据即可复用。脚本演示了从遍历图片文件夹到创建Word文档、插入图片、添加并填充表格的完整流程涉及Document、add_picture、add_table、Inches等核心API的用法代码注释清晰、逻辑直接。对需要自动生成工资通知、报表或希望了解python-docx常用功能的办公人员可对照示例脚本修改路径和数据快速迁移到自己的文档批量处理任务中。 干了这么多年Python自动化我发现最容易被低估的需求不是写爬虫、做数据分析而是把一堆乱七八糟的素材高效整理成规范的Word文档。前阵子同事拿着一批产品实拍图和Excel表找到我说周末必须把所有图片和表格按产品编号拼成Word文档还要按区域打包发给不同负责人。这种活儿听起来不复杂但真手动做一遍几百张图片对着表格拖来拖去眼睛不花才怪。好在我手边有python-docx和zipfile这对老搭档半小时不到就把流程跑通了还把“批量把图片和表格写入Word最后压缩成zip”做成了一个可复用的脚本。这篇文章就把这套方案从思路到踩坑完整拆给你看如果你也在做文档批量生成、产品手册、实验记录这类工作可以直接拿来改着用。1. 项目背景与整体思路解析1.1 这个脚本到底解决了什么问题先说具体场景。假设你手头有一份Excel表每一行是一条产品记录包含产品编号、名称、材质、尺寸、价格等字段同时还有一个images文件夹里面放着以产品编号开头的多张图片比如“P001_主图.jpg”“P001_细节图.jpg”。你的任务是把每条记录生成一份Word文档文档上半部分是相关图片下半部分是产品参数表格最后所有文档按业务分组压缩成zip压缩包。如果只有十几条记录手动操作还能忍一旦到了几百条甚至上千条人工操作不仅慢而且容易漏图、错行。这个脚本的价值就是把上面的过程自动化。它用python-docx库创建和编辑Word文档用pandas读取Excel表格再根据产品编号自动匹配图片并插入到Word中。每一份文档的名称用产品编号命名这样归档和查找都很直观。最后用zipfile库把所有Word文件打成一个zip包方便在微信、网盘、邮件里分发。整个过程不需要打开Office也不用手动调整任何格式跑一遍脚本喝杯水就完事了。1.2 为什么选python-docx而不是其他工具Word自动化方案其实不少比如pandoc、docxtpl、python-docx甚至VBA。我最终选python-docx核心原因是它把Word文档的段落、表格、图片都抽象成了Python对象操作起来非常灵活。docxtpl更适合基于模板批量填充如果每个文档的结构完全一致、只有文字变化它确实更轻但如果还要动态插入多张图片、按数据内容动态调整表格行数python-docx的自由度更高。pandoc适合把Markdown或HTML转成Word但处理复杂页眉页脚、单元格合并、图片尺寸控制时比较头疼。再说打包zipfile是Python内置库压缩docx文件没有任何额外依赖。这里有个很多人都忽略的细节docx文件本质上就是一个zip压缩包里面装的是各种XML文件。你再用zipfile把多个docx包成一个外层zip完全不会冲突而且压缩体积通常比原始文件小不少传文件时特别方便。2. 环境准备与基础配置2.1 搭建Python环境和安装依赖开始写代码前先把环境准备好。假设你用的是Python 3.9以上版本这是目前python-docx兼容性最好的区间。安装第三方库只需要两条命令pip install python-docx pandas如果Excel文件是.xlsx格式pandas底层会调用openpyxl通常不需要额外安装但如果你的环境比较干净也可以主动装一下pip install openpyxl这里提醒一句python-docx只支持处理.docx格式如果你手头的是老式.doc文件它直接报错。遇到这种情况要么让提供方重新存成.docx要么先用WPS或Office批量转格式然后再进脚本。早期我踩过这个坑写好的脚本一跑报错查了十分钟才发现源文件是.doc。2.2 设计目录结构和文件命名规范自动化脚本最怕的就是输入不规整所以目录结构和命名规则必须提前定好。我用的是这套结构project/ ├── images/ # 所有图片放在这里 ├── data.xlsx # 产品信息Excel表 ├── output_docs/ # 生成的Word文档放这里 ├── output_zips/ # 最终zip包输出到这里 └── build_report.py # 主脚本图片命名建议用“产品编号_序号.后缀”的格式比如“P001_01.jpg”“P001_02.png”。如果图片命名乱七八糟脚本匹配时会非常痛苦。Excel表至少要有一个列是产品编号字段名最好是英文或拼音避免编码不一致。比如用product_id不要用“产品编号中文”这种带括号的名字因为pandas读取后还要做字符串匹配符号不同容易出错。3. 核心实现批量把图片和表格写入Word3.1 先跑通一个最小Word生成流程别一上来就写完整脚本先从一个最简单的小例子验证环境。下面这段代码能创建一份空Word文档添加标题和一段文字然后保存from docx import Document doc Document() doc.add_heading(产品图片报告, level0) doc.add_paragraph(这是由Python自动生成的文档。) doc.save(test.docx)跑完这段代码看一眼生成的test.docx如果能在Word里正常打开说明python-docx安装成功。接下来就慢慢往里面加图片和表格。我习惯先跑通这个小例子再逐步加功能不然一次性写几百行代码出了问题都不好定位。3.2 批量插入图片的完整写法python-docx插入图片的核心方法是add_picture但直接调用只能把图片加到文档末尾还不能控制大小和居中。我通常封装一个add_image_section函数先添加一个居中的段落再往段落里插入图片并且强制设置图片宽度。from docx import Document from docx.shared Inches from docx.enum.text import WD_ALIGN_PARAGRAPH def add_centered_image(doc, image_path, width_inches5.5): paragraph doc.add_paragraph() paragraph.alignment WD_ALIGN_PARAGRAPH.CENTER run paragraph.add_run() run.add_picture(image_path, widthInches(width_inches))这里有个关键参数图片宽度。我一般设成5.5英寸左右既能清晰展示也不会超出Word默认页面的有效宽度。如果你的图片比较多建议先按产品编号筛选出这个产品对应的所有图片再按文件名里的序号排序这样插入文档后顺序是固定的。from pathlib import Path import re image_dir Path(images) def get_images_for_product(product_id): images sorted(image_dir.glob(f{product_id}_*)) # 按文件名最后两位序号排序避免1、10、2的字典序问题 images.sort(keylambda x: int(re.search(r_(\d)\., x.name).group(1))) return images实际生成文档时可以先添加一个“产品图片”的小标题然后遍历这个产品对应的图片列表一张张插入。注意如果某个产品一张匹配的图片都没有不要直接跳过最好生成一份只有表格、没有图片的文档并且在表格里加一列“是否有图”做标记方便后续补素材。3.3 从Excel读取数据并写入Word表格表格部分的实现核心是把DataFrame中的一行数据转换成一个Word表格。python-docx创建表格有两种方式一种是用add_table(rows1, colsn)先建一个空表再填充另一种是直接用add_table(styleTable Grid)再逐行添加。我常用第一种因为可以顺手设置表头。from docx import Document def add_product_table(doc, product_data): # product_data是dictkey为列名value为值 columns list(product_data.keys()) table doc.add_table(rows1, colslen(columns)) table.style Light Grid Accent 1 # 设置表头 hdr_cells table.rows[0].cells for i, col_name in enumerate(columns): hdr_cells[i].text str(col_name) # 设置数据行 row_cells table.add_row().cells for i, col_name in enumerate(columns): value product_data.get(col_name, ) row_cells[i].text if value is None else str(value) return table读取Excel的时候有个容易被忽视的问题pandas读出来的空值类型是NaN直接转成字符串会变成“nan”难看得要死。所以写入表格前要提前处理import pandas as pd df pd.read_excel(data.xlsx, dtypestr) df df.fillna() records df.to_dict(orientrecords)dtypestr这一行很关键它能避免Excel里的长数字被科学计数法显示。比如产品编号“P001”不会被误读成数字如果编号是一串纯数字如“123456”pandas默认会读成float变成“123456.0”这绝对不是你想要的。所以读取时直接指定dtypestr一劳永逸。3.4 一个产品生成一份Word文档的主循环把前面的零散函数拼起来核心流程就清晰了。主循环要做的只有四件事读取数据、匹配图片、生成文档、保存文档。from docx import Document for record in records: product_id record[product_id] doc Document() doc.add_heading(product_id, level1) doc.add_heading(产品图片, level2) images get_images_for_product(product_id) if images: for img in images: add_centered_image(doc, str(img)) else: doc.add_paragraph(该产品暂无图片) doc.add_heading(产品参数, level2) add_product_table(doc, record) doc.save(foutput_docs/{product_id}.docx)这段代码跑完之后output_docs目录下就出现了和Excel记录数量相同的Word文档。如果Excel里有500条记录就会生成500个docx文件每条记录的文件名就是产品编号找起来非常方便。这里有一个优化点如果产品编号中带有“/”“\”“:”等特殊字符Windows文件名会报错。稳妥做法是把这些字符替换成下划线。4. 打包归档与自动化扩展4.1 用zipfile把生成的Word文档打包Word文档生成完了接下来的任务是把这些文档按照业务要求打包。最简单的需求是把所有Word文档打成一个zip包我记得用zipfile实现这个操作不超过十行代码import zipfile from pathlib import Path output_docs Path(output_docs) with zipfile.ZipFile(output_zips/全部文档.zip, w, zipfile.ZIP_DEFLATED) as zf: for doc_file in sorted(output_docs.glob(*.docx)): zf.write(doc_file, arcnamedoc_file.name)ZIP_DEFLATED参数表示用DEFLATE算法压缩对docx这种本身已经是zip的文件压缩率虽然有限但也能省一点点空间。更重要的是把几十份文档打包成一个zip之后传输体验好了太多不用挨个文件传。如果还需要按区域分组打包比如Excel表里有“region”列那就根据region字段分别建子文件夹再逐一打包import zipfile from pathlib import Path output_docs Path(output_docs) def pack_docs(doc_files, zip_name): with zipfile.ZipFile(zip_name, w, zipfile.ZIP_DEFLATED) as zf: for doc_file in doc_files: zf.write(doc_file, arcnamedoc_file.name) for region in df[region].unique(): files [output_docs / f{pid}.docx for pid in df.loc[df[region] region, product_id]] pack_docs(files, foutput_zips/{region}_文档.zip)这样每个负责人收到一个zip包包里的文档都是自己区域的方便又清晰。4.2 给脚本加上命令行参数和定时任务为了让脚本能被更多人使用我习惯用argparse加几个命令行参数让用户不需要改代码就能调整输入输出目录。import argparse parser argparse.ArgumentParser(description批量生成Word产品报告) parser.add_argument(--excel, defaultdata.xlsx) parser.add_argument(--image-dir, defaultimages) parser.add_argument(--output-dir, defaultoutput_docs) parser.add_argument(--zip-dir, defaultoutput_zips) args parser.parse_args()参数化之后Windows里可以建一个“批量生成.bat”文件内容写python build_report.py --excel data.xlsx --image-dir images --output-dir output_docs --zip-dir output_zips pause双击就能跑。Linux服务器上也可以直接用crontab定时执行比如每天凌晨两点自动根据最新的Excel生成当天报告0 2 * * * cd /home/yourname/report_project python build_report.py logs/report.log 21自动化做到这个程度基本上就是“扔进一个Excel等一会儿拿zip”的状态了。4.3 大批量处理时的并发优化思路如果产品数量特别多比如几千个文档、上万张图片单线程跑会比较慢。主要耗时在图片读取和磁盘IO上。一个可行的优化是用concurrent.futures的ProcessPoolExecutor来做多进程处理但要注意python-docx本身不是完全线程安全的我建议用进程池而不是线程池。from concurrent.futures import ProcessPoolExecutor def generate_one(record): # return record包含product_id等字段 # 这里完整执行生成单个文档的逻辑 pass with ProcessPoolExecutor(max_workers4) as executor: executor.map(generate_one, records)多进程模式下每个进程独立创建Document对象互不干扰。同时如果有几百张高清图生成出来的Word文件会非常大打开也慢。我一般会在插入图片前用PIL先统一缩放到宽度1200像素左右再插入Word这样既能保证清晰度又能显著降低文件体积。当然如果业务要求原图这一步就略过。5. 常见问题与排查技巧5.1 图片路径报错或插入后显示为空白这个问题最常见的原因有两个。第一图片路径是用相对路径写的但脚本当前工作目录和执行目录不是同一个。最好在脚本开头用BASE_DIR Path(__file__).parent定位脚本所在目录所有路径都基于BASE_DIR拼接这样不管是直接执行还是被别的脚本调用都不会跑偏。第二图片后缀和实际格式不一致。比如文件名写的是.jpg实际文件是PNG格式python-docx可能会跳过或报错。遇到这种问题可以先打印图片列表再逐个检查是否存在或者干脆把图片目录下的文件后缀统一改掉。我在代码里加过一段防御逻辑插入前先判断文件是否存在不存在就记录到日志里。5.2 Word表格列宽和样式不对表格插入后经常出现“整张表占满一页、列宽参差不齐”的情况。这是因为python-docx默认表格宽度是自动的。要手动控制列宽需要关闭表格自动调整并逐列设置宽度from docx.shared import Cm table.autofit False table.allow_autofit False widths [Cm(2), Cm(4), Cm(3), Cm(3)] for row in table.rows: for idx, width in enumerate(widths): row.cells[idx].width width注意如果你只设表头那一行的宽度数据行的宽度可能不会跟着变。所以得遍历每一行去设置。另外单元格内容如果是一长串没有空格的网址或编号会把表格撑破建议在代码里给长文本手动加入换行符或者在单元格里设置较小的字号。5.3 中文内容乱码异常python-docx写入中文后Word打开出现乱码这种情况极少因为docx内部本身就是Unicode XML。但如果你读Excel时出现乱码大概率是Excel文件编码不是UTF-8。用pandas读取时可以尝试指定引擎或编码df pd.read_excel(data.xlsx, dtypestr, engineopenpyxl)如果是从CSV文件读数据那就得注意编码了常见的是encodingutf-8或encodinggbk。另外生成Word后如果发现中文字体显示的是默认英文样式可以用下面的代码设置中文字体from docx.oxml.ns import qn run.font.name 宋体 run._element.rPr.rFonts.set(qn(w:eastAsia), 宋体)虽然不影响内容正确性但商务文档对字体还是有要求的这个细节别忽略。5.4 生成的Word文件太大或生成缓慢如果每个产品的图片有十张以上而且都是几兆的高清原图最终docx体积可能会超过50MB。不仅脚本跑得慢Word打开也会卡。我现在的处理习惯是在插入图片前先用PIL做统一尺寸压缩把最长边缩到1500像素以内保存为JPEG质量85肉眼几乎看不出差别但体积能缩小70%以上。from PIL import Image def resize_image(src_path, dst_path, max_width1500): img Image.open(src_path) if img.width max_width: ratio max_width / img.width new_size (max_width, int(img.height * ratio)) img img.resize(new_size, Image.LANCZOS) img.save(dst_path, quality85, optimizeTrue) else: img.save(dst_path)如果图片数量特别多建议生成过程中直接写一个resized_images缓存目录避免每次重复压缩同一张图片省时省力。6. 实操总结与个人体会这套脚本前前后后帮我处理过好几波产品文档生成任务最深刻的体会是自动化办公的核心不是炫技而是把输入规范定清楚。图片命名、Excel列名、输出目录这些看起来不起眼的细节才是整个流程能否跑通的关键。早期我接手同事的图片时命名乱七八糟有叫“未命名1.jpg”的也有叫“新建文档.jpg”的脚本匹配图片时不仅慢还会漏。后来我干脆在项目里加了一个命名校验函数凡是匹配不到图片的记录直接输出警告这才慢慢把脏数据过滤干净。如果你准备自己搭一套这样的批量生成流程我的建议是千万不要一开始就处理全量数据。先拿两三条记录跑通最小闭环确认图片、表格、打包三个环节都正常再扩展到完整数据。这样即使出问题也能迅速定位到底是数据问题、代码问题还是图片格式问题。等你把这条流水线跑顺了你就知道Python自动办公到底能为重复劳动省下多少时间了。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价