简介:这是一份面向Python初学者与数据处理入门者的Excel读写实战脚本合集,针对日常数据分析、报表自动化等场景中频繁出现的表格读取与写入需求,提供可直接运行的代码参考。压缩包共4个文件,全部为py脚本,整体约6KB,涵盖读取Excel、读取数值型数据、读取并处理表格以及读写结合等典型用法,便于按需查阅与二次修改。资源围绕pandas与openpyxl两大常用库展开,既演示read_excel、to_excel等基础接口,也涉及条件筛选、单元格遍历、工作簿创建与保存等操作,帮助读者理解DataFrame与工作表对象之间的差异。目前已有702人学习下载,适合希望快速上手Excel自动化处理、积累脚本模板的开发者参考借鉴。
1. 从一份“python读取Excel并写入.zip”说起:它到底能帮你省下多少手工活
如果你日常要处理报表、台账、对账单,大概率遇到过这种场景:业务方丢来一个几十兆的 Excel,里面七八个 sheet,字段命名五花八门,你要把其中几张表按条件筛出来,再拼到另一份模板里发回去。手工复制粘贴不仅慢,还容易在筛选条件上翻车。这份“python读取Excel并写入.zip”就是冲着这类重复劳动来的——它把读取、清洗、写入这条链路打包成可直接复用的脚本集合,核心依赖是 pandas 加 openpyxl,覆盖 xlsx 与 xls 两种常见格式。适合谁?会一点 Python 基础、但没系统写过 Excel 批处理的人;也适合已经用 pandas 但总在日期格式、合并单元格、多 sheet 写入上踩坑的熟手。它解决的不是“能不能读”的问题,而是“读进来之后怎么稳定写出去”的问题。
2. 读取环节:pandas.read_excel 的参数怎么配才不翻车
2.1 先搞清楚你的 Excel 到底长什么样
很多人拿到文件直接pd.read_excel("data.xlsx"),结果第一行是标题、第二行是空行、第三行才是表头,读出来列名全是Unnamed: 0。这不是 pandas 的锅,是你没告诉它表头在第几行。常见做法是先手动打开文件看一眼结构,再用header参数指定。如果文件里有多个 sheet,sheet_name不写默认只读第一个,写None会返回一个字典,key 是 sheet 名,value 是对应 DataFrame。这个字典结构在后续按 sheet 分别处理时特别顺手。
import pandas as pd # sheet_name=None 返回字典,适合多 sheet 批量处理 sheets = pd.read_excel( "source.xlsx", sheet_name=None, # 读所有 sheet header=2, # 表头在第 3 行(索引从 0 开始) dtype={"订单号": str} # 强制订单号为字符串,防止前导零丢失 ) for name, df in sheets.items(): print(name, df.shape)逻辑说明:sheet_name=None是批量读取的关键,省去逐个指定名字的麻烦。header=2对应人类视角的第 3 行,索引从 0 起算。dtype参数容易被忽略,但订单号、身份证号、银行卡号这类字段一旦被识别成数字,前导零会消失,后续写入再读就对不上。参数怎么改:如果表头就在第一行,header用默认的 0;如果文件没有表头,设header=None,再自己传names列表。
2.2 日期列和合并单元格是两个高频雷区
Excel 里的日期在底层是序列号,pandas 读进来可能是datetime,也可能是int,取决于单元格格式和 openpyxl 的解析结果。稳妥做法是读完后统一用pd.to_datetime转一次,并指定errors="coerce",把转不了的变成 NaT,方便后续排查。合并单元格更麻烦:pandas 只会把值放在合并区域的左上角,其余位置是 NaN。如果你需要向下填充,用ffill(),但要注意它会把整列都填满,包括本来就不该有值的行。我一般会先确认合并范围,再决定是填充还是直接丢弃。
# 日期统一转换,转不了的置为 NaT df["下单日期"] = pd.to_datetime(df["下单日期"], errors="coerce") # 合并单元格向下填充,仅对指定列操作 df["所属区域"] = df["所属区域"].ffill() # 检查填充后是否还有空值 print(df["所属区域"].isna().sum())逻辑说明:errors="coerce"是后悔药,避免因为一个脏日期导致整个脚本报错中断。ffill()只对所属区域这一列生效,不会污染其他列。参数怎么改:如果合并单元格是横向的,用bfill(axis=1);如果填充后仍有关键列为空,说明源文件本身有缺失,需要回到业务侧确认,而不是在脚本里硬填。
3. 写入环节:to_excel 的坑比读取只多不少
3.1 多 sheet 写入与追加模式
to_excel默认会覆盖同名文件,如果你想把多个 DataFrame 写进同一个文件的不同 sheet,必须用ExcelWriter上下文管理器。这里有个血泪经验:mode="a"追加模式在 openpyxl 引擎下对已存在的文件支持并不完美,尤其是文件本身有格式、有公式的时候,追加写入可能破坏原有内容。常见做法是:要么一次性把所有 sheet 写进新文件,要么先读原文件所有 sheet,合并新数据后再整体覆盖写回。
with pd.ExcelWriter("output.xlsx", engine="openpyxl") as writer: df_summary.to_excel(writer, sheet_name="汇总", index=False) df_detail.to_excel(writer, sheet_name="明细", index=False) # 调整列宽(openpyxl 原生操作) worksheet = writer.sheets["汇总"] worksheet.column_dimensions["A"].width = 20逻辑说明:with语句保证文件句柄正确关闭,避免写一半进程退出导致文件损坏。index=False是绝大多数场景下的正确选择,除非你确实需要保留行号。列宽调整需要拿到writer.sheets里的 worksheet 对象,这是 openpyxl 的能力,pandas 本身不提供。参数怎么改:如果输出文件要给非技术同事看,建议加上freeze_panes冻结首行,但注意这个参数在不同 pandas 版本里位置有变化,写之前先确认版本。
3.2 格式保留与大数据量分块
如果你需要保留源文件的字体、颜色、边框,pandas 的to_excel做不到,它只写值。这时候要么用 openpyxl 直接操作单元格,要么用 xlsxwriter 引擎配合add_format。另一个现实问题是数据量:几万行以内,to_excel没问题;几十万行,内存和写入时间都会明显上升。我一般会先按业务维度拆分,或者直接输出 CSV 给下游,Excel 只作为最终展示层。
# 大数据量分块写入,避免一次性占用过多内存 chunk_size = 50000 with pd.ExcelWriter("big_output.xlsx", engine="openpyxl") as writer: for i, chunk in enumerate(pd.read_excel("big_source.xlsx", chunksize=chunk_size)): chunk.to_excel(writer, sheet_name=f"part_{i}", index=False)逻辑说明:chunksize是read_excel的参数,返回一个迭代器,每次只加载指定行数。写入时按 chunk 分 sheet,既控制内存,也方便后续定位问题数据在哪一块。参数怎么改:chunk_size根据机器内存调整,一般 5 万到 10 万行比较稳;如果 sheet 数量有上限要求,可以改成追加到同一个 sheet,但需要手动控制startrow。
4. 避坑与排查:那些让我加班到凌晨的 Excel 问题
4.1 现象:读进来列名多了 Unnamed,原因:表头行判断错误
这是最高频的问题。源文件第一行可能是标题、第二行是空行、第三行才是真正的表头。pandas 默认把第一行当表头,于是空行和标题行都变成了列名。解决方式是先手动确认表头位置,用header参数指定;如果表头行不固定,可以先header=None读进来,再用iloc定位表头行,重新赋值columns。
4.2 现象:写入后日期变成数字,原因:Excel 序列号未转换
用 openpyxl 直接写datetime对象时,如果单元格格式没设成日期,Excel 会显示成序列号。pandas 的to_excel一般会处理好,但如果你手动用 openpyxl 写,需要设置number_format。排查方法是写完后用 Excel 打开看显示格式,或者用 pandas 再读一次,看读出来是datetime还是int。
4.3 现象:文件被占用无法写入,原因:Excel 进程未释放
Windows 下如果 Excel 还开着目标文件,Python 写入会抛PermissionError。这不是代码问题,是文件锁。解决方式是写入前确认文件已关闭,或者在脚本里加异常捕获,提示用户关闭文件后重试。我一般会在写入前先尝试重命名原文件,成功说明没被占用,失败就给出明确提示。
4.4 现象:中文列名写入后乱码,原因:编码或引擎不匹配
xlsx 本身是 zip 包,不存在传统编码问题,但如果你输出的是 CSV,to_csv默认 utf-8,Excel 打开可能乱码。解决方式是写 CSV 时加encoding="utf-8-sig",让 Excel 正确识别 BOM。xlsx 写入一般不会乱码,如果出现,检查是不是引擎选错了,xlsx 用 openpyxl,xls 用 xlwt。
4.5 现象:公式单元格读出来是公式字符串,原因:未启用 data_only
openpyxl 读取时默认返回公式本身,而不是计算结果。如果你需要的是值,加载工作簿时加data_only=True。但注意,这个参数依赖 Excel 上次保存时缓存了计算结果,如果文件是程序生成的、从未用 Excel 打开过,可能读出来是 None。稳妥做法是让上游确保公式已计算并保存。
5. 进阶技巧:用 openpyxl 做 pandas 做不到的格式控制
pandas 负责数据,openpyxl 负责格式,两者配合才能产出能直接发出去的报表。一个具体技巧是:先用 pandas 把数据写好,再用 openpyxl 加载输出文件,对特定列加条件格式、对表头加底色、对数字列设千分位。这样既保留了 pandas 的清洗效率,又补上了格式短板。
from openpyxl import load_workbook from openpyxl.styles import Font, PatternFill, numbers # pandas 写完后,用 openpyxl 二次加工 wb = load_workbook("output.xlsx") ws = wb["汇总"] # 表头加粗、灰底 header_fill = PatternFill("solid", fgColor="DDDDDD") for cell in ws[1]: cell.font = Font(bold=True) cell.fill = header_fill # 金额列设千分位格式 for row in ws.iter_rows(min_row=2, min_col=3, max_col=3): for cell in row: cell.number_format = numbers.FORMAT_NUMBER_COMMA_SEPARATED1 wb.save("output_formatted.xlsx")逻辑说明:load_workbook重新打开 pandas 写出的文件,此时数据已经就位,只需要处理样式。ws[1]取第一行所有单元格,批量设置字体和填充。number_format用 openpyxl 内置的常量,避免手写格式字符串出错。参数怎么改:如果表头不在第一行,调整ws[1]的行号;如果金额列位置变化,改min_col和max_col。注意wb.save会覆盖原文件,建议输出到新文件名,保留一份原始数据文件作为后悔药。
验证方法很简单:写完后用 pandas 再读一次输出文件,确认行数、列名、关键字段类型和源数据一致;再用 Excel 打开看格式是否符合预期。我一般会写一个assert检查行数,比如assert len(df_out) == len(df_in),不通过就直接报错,避免把错数据发出去。从那以后我每次处理 Excel 批处理,都强制先跑一遍读取验证再写入,宁可多花两分钟,也不想到半夜被叫起来重跑。希望帮到你。
本文还有配套的精品资源,点击获取