Python 读取 Excel 并写入 zip:自动化报表打包实战
简介这份资源面向需要处理表格数据的Python学习者与开发者聚焦Excel文件的读取与写入这一常见任务帮助解决数据分析、数据清洗与自动化报告中的表格操作问题。压缩包共4个文件全部为py脚本整体约6KB涵盖读取、按条件筛选、写入以及读写结合等不同操作示例便于按需查阅与直接运行。内容围绕pandas与openpyxl两个常用库展开pandas部分演示read_excel读取、条件筛选及to_excel写入openpyxl部分则涉及工作簿加载、单元格遍历与新建保存可帮助读者理解两种方案在简单表格与复杂格式场景下的差异。目前已有702人学习适合希望快速上手Excel自动化处理、积累脚本模板的初中级Python使用者参考。1. 用 Python 读取 Excel 并写入 zip一个被低估的自动化刚需财务同事每周五下午都要把 12 个区域的销售明细表汇总再打包成一个压缩包发给总部。手动操作是打开每个 xlsx复制粘贴到总表另存为右键压缩。一套流程 40 分钟错一个单元格就得重来。这种场景下用 Python 读取 Excel 并写入 zip 不是炫技而是把重复劳动压缩成一条命令的刚需。这个标题拆开看是两件事读 Excelpandas/openpyxl 负责和写 zip标准库 zipfile 负责。难点不在单个库怎么用而在两者衔接时的内存管理、路径处理和编码问题。适合有基础 Python 语法、日常要处理报表打包的运营、财务、数据分析从业者。下面按「读进来 → 处理好 → 压出去」的链路把每一步的参数和坑讲透。2. 读取 Excel 的三种姿势pandas、openpyxl 与 calamine 怎么选2.1 先搞清楚你的 Excel 到底长什么样选库之前先确认三件事文件是 .xlsx 还是 .xls、有没有合并单元格、单表数据量多大。.xls 是旧二进制格式pandas 需要 xlrd 才能读而新版 xlrd 已经放弃了对 xlsx 的支持这个历史包袱经常让人翻车。合并单元格在 pandas 里读出来是 NaN需要额外填充。数据量超过 10 万行时pandas 默认的全量加载会吃掉大量内存。我一般先用一条命令探底python -c import pandas as pd; df pd.read_excel(sample.xlsx, nrows5); print(df.shape); print(df.columns.tolist())nrows5只读前 5 行快速看列名和结构避免大文件全量加载。df.columns.tolist()打印列名列表确认表头在第几行——很多报表前两行是标题和空行直接读会把标题当列名。2.2 pandas 读取的核心参数与适用边界pandas 的read_excel是最省事的选择适合结构规整、单表不超过几十万行的场景。关键参数有四个import pandas as pd df pd.read_excel( sales_2024.xlsx, sheet_nameSheet1, # 指定工作表None 表示读全部 header0, # 表头所在行从 0 开始计数 usecolsA:F, # 只读 A 到 F 列减少内存 dtype{订单号: str}, # 强制订单号为字符串防止前导零丢失 engineopenpyxl # 显式指定引擎 ) print(df.head())sheet_name传字符串读单表传None返回一个字典键是表名、值是 DataFrame适合批量处理多 sheet。usecols用列字母或列名列表限定范围能显著降低内存。dtype是血泪经验订单号、身份证号这类字段如果被 pandas 推断成整数前导零会消失必须显式声明为 str。engine在 xlsx 场景下用 openpyxlxls 场景用 xlrd不指定时 pandas 会自动选但自动选偶尔会选错。读进来的 DataFrame 可以直接做筛选、合并、计算处理完再决定怎么写出去。2.3 openpyxl 直接操作单元格需要保留格式时的选择pandas 读进来的是纯数据原表的字体、颜色、公式全部丢失。如果压缩包里的 Excel 需要保留格式就得用 openpyxl 直接操作工作簿对象from openpyxl import load_workbook wb load_workbook(template.xlsx, data_onlyTrue) ws wb[Sheet1] # 遍历所有行跳过表头 for row in ws.iter_rows(min_row2, values_onlyTrue): order_id, amount, region row[0], row[1], row[2] if amount and amount 10000: print(f大额订单: {order_id} 金额 {amount} 区域 {region}) wb.save(filtered.xlsx)data_onlyTrue表示读取公式的计算结果而不是公式本身这个参数在读取别人发来的报表时特别重要否则你拿到的是SUM(A1:A10)这样的字符串。iter_rows的values_onlyTrue直接返回值元组比逐个访问cell.value快很多。openpyxl 的代价是速度慢10 万行以上会明显卡顿适合小批量、重格式的场景。2.4 大文件场景calamine 引擎的提速效果数据量到几十万行时pandas 默认的 openpyxl 引擎会慢到让人怀疑人生。python-calamine 是一个用 Rust 写的读取引擎pandas 2.2 之后可以直接通过enginecalamine调用import pandas as pd df pd.read_excel( big_data.xlsx, enginecalamine, usecols[日期, 金额, 区域] ) print(f读取完成共 {len(df)} 行)实测在 50 万行、20 列的 xlsx 上calamine 比 openpyxl 快 3 到 5 倍内存占用也更低。代价是需要额外安装python-calamine包且对某些冷门格式支持不如 openpyxl 完善。我的习惯是小文件用 openpyxl大文件先试 calamine遇到格式报错再退回 openpyxl。3. 把处理结果写进 zipzipfile 的四种写入模式3.1 从内存直接写入避免落盘的 BytesIO 方案最直觉的做法是先把 DataFrame 存成 xlsx 文件再压缩。但中间文件多了之后清理是个麻烦。更好的方式是用BytesIO在内存里完成 Excel 的序列化直接写进 zipimport pandas as pd from io import BytesIO from zipfile import ZipFile, ZIP_DEFLATED df pd.read_excel(source.xlsx) # 在内存中生成 xlsx buffer BytesIO() with pd.ExcelWriter(buffer, engineopenpyxl) as writer: df.to_excel(writer, indexFalse, sheet_name汇总) buffer.seek(0) # 关键把指针拨回开头 # 写入 zip with ZipFile(output.zip, w, compressionZIP_DEFLATED) as zf: zf.writestr(汇总表.xlsx, buffer.read()) print(打包完成)BytesIO是一个内存中的二进制流ExcelWriter把 DataFrame 写进去之后指针停在末尾必须seek(0)拨回开头否则read()读到的是空内容——这个坑我踩过不止一次。writestr的第一个参数是压缩包内的文件名可以带路径如2024/汇总表.xlsxzipfile 会自动创建目录结构。ZIP_DEFLATED是压缩算法对 xlsx 这种本身已压缩的格式压缩率有限但聊胜于无。3.2 多文件批量打包循环写入与命名规范实际场景往往是把多个处理结果打进一个包。用循环配合writestr即可import pandas as pd from io import BytesIO from zipfile import ZipFile, ZIP_DEFLATED regions [华东, 华南, 华北, 西南] source pd.read_excel(all_sales.xlsx) with ZipFile(regional_reports.zip, w, compressionZIP_DEFLATED) as zf: for region in regions: subset source[source[区域] region] if subset.empty: continue # 空数据跳过避免生成空文件 buf BytesIO() with pd.ExcelWriter(buf, engineopenpyxl) as writer: subset.to_excel(writer, indexFalse, sheet_nameregion) buf.seek(0) zf.writestr(f{region}_销售明细.xlsx, buf.read()) print(f{region}: {len(subset)} 行已写入)subset.empty判断很关键某些区域可能没有数据生成一个空 xlsx 既占空间又让接收方困惑。文件名用 f-string 拼接区域名保证压缩包内文件可读。循环内每次新建BytesIO不要复用同一个 buffer否则会读到上一次的残留数据。3.3 压缩级别与文件名的三个细节ZipFile的compresslevel参数控制压缩级别取值 0 到 9默认是 None相当于 6from zipfile import ZipFile, ZIP_DEFLATED # 高压缩适合归档 with ZipFile(archive.zip, w, compressionZIP_DEFLATED, compresslevel9) as zf: zf.write(report.xlsx, arcname2024年度报告.xlsx)compresslevel9压缩率最高但耗时最长compresslevel1最快但文件大。对 xlsx 来说因为内部已经是 zip 格式再压缩收益很小我一般用默认值。arcname参数指定文件在压缩包内的名字不指定则用原路径容易带上一长串本地目录。中文文件名在 zipfile 里默认用 UTF-8 编码Windows 自带解压工具可能显示乱码接收方用 7-Zip 或 Bandizip 打开正常。3.4 追加与更新a 模式与重复写入的陷阱ZipFile的a模式可以在已有压缩包上追加文件from zipfile import ZipFile, ZIP_DEFLATED with ZipFile(output.zip, a, compressionZIP_DEFLATED) as zf: zf.write(new_report.xlsx, arcname补充报表.xlsx)注意如果压缩包里已经存在同名文件追加不会覆盖而是出现两个同名条目解压时后者覆盖前者行为取决于解压工具。要更新文件必须先读出全部内容、删掉旧条目、重新写入或者干脆重建整个 zip。我一般不在原包上追加而是每次生成新包避免这种玄学问题。4. 避坑指南编码、内存与路径的五个真实翻车现场4.1 中文文件名在 Windows 解压后变乱码现象Python 生成的 zip 在 Windows 资源管理器里解压中文文件名显示为乱码用 7-Zip 打开却正常。原因是 zipfile 默认用 UTF-8 编码文件名而 Windows 自带解压工具按本地代码页解析。解决方式是在写入时显式指定编码或者干脆用英文文件名加一个中文映射表。我的做法是压缩包内文件名用拼音或英文在包内附一个manifest.txt说明对应关系接收方一看就懂。4.2 BytesIO 忘记 seek(0) 导致写入空文件现象压缩包生成了但里面的 xlsx 打开是空白。原因就是前面提到的ExcelWriter写完后指针在末尾read()返回空字节。解决每次read()之前调用buffer.seek(0)。这个错误不报异常只是静默生成空文件排查起来很费时间。养成习惯凡是 BytesIO 读写切换先 seek。4.3 大文件全量加载导致内存溢出现象处理 100 万行的 xlsx 时进程被系统杀掉。原因是 pandas 默认全量加载100 万行 30 列大约占用 2 到 3 GB 内存。解决用read_excel的usecols限定列用chunksize分块读取注意 read_excel 的 chunksize 返回的是迭代器或者换 calamine 引擎降低内存占用。如果只是筛选后打包根本不需要全量加载分块处理完直接写 zip 即可。4.4 日期列读出来变成数字现象Excel 里的日期2024-01-15读进来变成45306。原因是 Excel 内部用序列号存储日期openpyxl 在某些配置下不自动转换。解决读取后用pd.to_datetime(df[日期], unitD, origin1899-12-30)转换或者在read_excel里指定parse_dates[日期]。注意 origin 是 1899-12-30 而不是 1900-01-01因为 Excel 有一个著名的 1900 闰年 bug。4.5 压缩包内路径用了反斜杠现象在 Windows 上开发压缩包内文件名写成reports\\summary.xlsx在 Linux 上解压变成一个名字里带反斜杠的文件。原因是 zip 规范要求路径分隔符用正斜杠/。解决统一用os.path.join或 pathlib 生成路径后把反斜杠替换成正斜杠或者直接用 f-string 写reports/summary.xlsx。跨平台代码里路径拼接永远用正斜杠。5. 进阶技巧用上下文管理器封装一个可复用的打包函数把前面的逻辑封装成一个函数是让这套方案真正可复用的关键。下面这个函数接收一个 Excel 路径和分组列名按分组拆表并打包全程内存操作不落中间文件import pandas as pd from io import BytesIO from zipfile import ZipFile, ZIP_DEFLATED from pathlib import Path def excel_to_zip_by_group( excel_path: str, group_col: str, output_zip: str, sheet_name: str Sheet1, compress_level: int 6 ) - int: 按指定列分组将每组数据写入独立 xlsx 并打包成 zip。 返回写入的文件数量。 df pd.read_excel(excel_path, sheet_namesheet_name) if group_col not in df.columns: raise ValueError(f列 {group_col} 不存在实际列: {df.columns.tolist()}) count 0 with ZipFile(output_zip, w, compressionZIP_DEFLATED, compresslevelcompress_level) as zf: for name, group in df.groupby(group_col): buf BytesIO() with pd.ExcelWriter(buf, engineopenpyxl) as writer: group.to_excel(writer, indexFalse, sheet_namestr(name)[:31]) buf.seek(0) safe_name str(name).replace(/, _).replace(\\, _) zf.writestr(f{safe_name}.xlsx, buf.read()) count 1 return count if __name__ __main__: n excel_to_zip_by_group(all_sales.xlsx, 区域, regional.zip) print(f共打包 {n} 个文件)几个设计细节值得说。sheet_namestr(name)[:31]是因为 Excel 工作表名上限 31 个字符超长会报错。safe_name把分组名里的斜杠替换掉防止路径穿越或非法文件名。groupby默认会排除 NaN 分组如果分组列有空值这些行会被静默丢弃需要提前用fillna(未知)处理。返回文件数量方便调用方做校验。验证方法很简单生成 zip 后用ZipFile.namelist()打印条目列表再逐个read()出来用 pandas 读一遍确认行数和原数据一致from zipfile import ZipFile import pandas as pd from io import BytesIO with ZipFile(regional.zip) as zf: for name in zf.namelist(): data pd.read_excel(BytesIO(zf.read(name))) print(f{name}: {len(data)} 行, 列: {data.columns.tolist()})这套流程我用了两年多最大的教训是不要相信 Excel 的表头一定在第一行也不要想当然认为分组列没有空值。每次处理新报表先跑一遍探查命令确认结构再写正式逻辑。另一个习惯是压缩包内永远附一个manifest.txt记录生成时间、数据行数和分组依据接收方出问题时能快速定位。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

Terminus(Olares)RabbitMQ 中间件集成实战:用 OlaresManifest.yaml 声明式接入消息队列

Terminus(Olares)RabbitMQ 中间件集成实战:用 OlaresManifest.yaml 声明式接入消息队列

云原生后端运维 【免费下载链接】Terminus Open-Source Personal Cloud OS for Always-On Agents 项目地址: https://gitcode.com/gh_mirrors/terminus2/Terminus 点击查看 免费下载 本篇技术指南基于 Terminus 仓库中 RabbitMQ 集成文档 展开,讲解如何…

2026/10/14 17:36:00 阅读更多 →
九轴姿态解算实战:C语言实现Mahony互补滤波与四元数融合

九轴姿态解算实战:C语言实现Mahony互补滤波与四元数融合

简介:九轴姿态解算源代码是一套面向嵌入式开发、无人机及机器人等场景的C语言实现,融合加速度计、磁力计与陀螺仪数据,用于实时估计物体的横滚、俯仰与偏航角。资源包含4个文件,全部为2个C源文件和2个头文件,压缩包仅5…

2026/10/14 17:36:00 阅读更多 →
C#工业级图形面积周长计算:精度、鲁棒性与性能平衡

C#工业级图形面积周长计算:精度、鲁棒性与性能平衡

1. 项目概述:为什么一个“图形周长、面积计算”功能值得花时间深挖? 你可能第一眼看到“C# 图形周长、面积计算”这个标题,会下意识觉得:“不就是几个数学公式封装成方法吗?勾股定理、πr、底高2……抄一遍就完事。”我…

2026/10/14 17:34:59 阅读更多 →

最新新闻

快速阅读不靠眼快:筛选与理解的实用框架

快速阅读不靠眼快:筛选与理解的实用框架

经常有人问我:“你读书怎么那么快?是不是一目十行、走马观花?”说实话,我刚开始试水快速阅读的时候也踩过不少坑,最典型的表现是字都看完了,合上书一问三不知。后来我花了很长时间去拆解“快速阅读”和“快…

2026/10/14 18:20:44 阅读更多 →
存量市场服务升级:低风险高回报的商业模式

存量市场服务升级:低风险高回报的商业模式

1. 为什么说"稳妥生意"比创业更值得关注最近三年,我身边有37位朋友尝试创业,最终存活下来的只有3家。这个残酷的数字让我开始思考:对于大多数普通人来说,是否存在着比创业风险更低、回报更稳定的商业机会?经…

2026/10/14 18:20:44 阅读更多 →
Decepticon 实战手册:EtherNet/IP + CIP 协议攻击全流程(44818/2222 端口下的 PLC 侦察、标签读写与模式切换)

Decepticon 实战手册:EtherNet/IP + CIP 协议攻击全流程(44818/2222 端口下的 PLC 侦察、标签读写与模式切换)

【免费下载链接】Decepticon Autonomous Hacking Agent for Red Team 项目地址: https://gitcode.com/gh_mirrors/de/Decepticon 点击查看 免费下载 本指南基于 Decepticon 仓库中 enip-cip 技能文档 编写,系统讲解针对北美工业控制系统(ICS…

2026/10/14 18:20:44 阅读更多 →
中点画圆算法详解:光栅化生成完美圆的数学原理与代码实现

中点画圆算法详解:光栅化生成完美圆的数学原理与代码实现

圆的生成算法,是计算机图形学课程里最容易被低估的一个实验。很多同学看到“画圆”两个字,第一反应是直接调用窗口库里的画圆函数,几行代码就结束。但实验真正要你做的,是把它当成一道光栅化算法题:输入圆心坐标、半径…

2026/10/14 18:20:44 阅读更多 →
把“学术导航仪”装进书匠策AI:一篇期刊论文的“造路”逻辑

把“学术导航仪”装进书匠策AI:一篇期刊论文的“造路”逻辑

官网直达:www.shujiangce.com 微信公众号搜一搜:书匠策AI 写期刊论文最折磨人的,从来不是“写”这个动作本身。 是你盯着空白文档,知道要做文献综述,却不知道从哪篇开始;知道要有理论框架,却拿…

2026/10/14 18:20:44 阅读更多 →
插件加载失败排查:从生命周期到激活机制,一篇搞定

插件加载失败排查:从生命周期到激活机制,一篇搞定

先说一句,我带过好几个插件化改造的项目,也修过无数跟插件相关的启动报错,所以看到 "failed to load plugins web boot: 2 entries did not activate" 这种日志时,第一反应不是翻框架文档,而是看插件的激活方…

2026/10/14 18:19:43 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/13 22:01:27 阅读更多 →
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/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练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/14 7:53:34 阅读更多 →