用pd.ExcelWriter配合openpyxl是唯一可行路径,因to_excel()无法写入多表头或样式,而openpyxl支持合并单元格、样式设置等,且需注意版本兼容性、手动写表头、逐单元格设样式及必须调用writer.close()。

用 pd.ExcelWriter 配合 openpyxl 是唯一可行路径
纯 to_excel() 无法写入多表头(即合并单元格的层级标题)或样式,它只负责数据落盘。必须借助 ExcelWriter 引擎控制底层写入逻辑,而 openpyxl 是目前唯一支持写入样式、合并单元格、字体/边框/填充色的引擎(xlsxwriter 不支持读取/修改已有单元格,也**不支持合并单元格写入**)。
安装时确认: pip install openpyxl,且 Pandas 版本 ≥ 1.3.0(旧版对 openpyxl 的兼容性差,易报 AttributeError: 'Worksheet' object has no attribute 'merge_cells')。
写多表头:先用 to_excel() 写空结构,再用 openpyxl 合并单元格
Pandas 本身不提供“生成带合并的多级列头”能力。常见错误是直接传 MultiIndex 列并设 header=[0,1]——这只会写出两行普通文本,不会合并单元格,视觉上仍是平铺的。
- 先调用
df.to_excel(writer, sheet_name='Sheet1', header=False, index=False),把数据区域“裸写”进去(跳过 Pandas 自动写 header) - 用
writer.sheets['Sheet1']获取openpyxl.worksheet.worksheet.Worksheet对象 - 手动写入表头文字,并调用
.merge_cells(),例如:第一级表头跨 3 列就写ws.merge_cells('A1:C1'),第二级对应填入A1、B1、C1 - 注意行列索引从 1 开始(
openpyxl坐标系),Pandas 写入的数据默认从第 2 行开始(第 1 行留给表头),所以表头写在row=1,数据从row=2起
加样式:只能逐单元格设置,不能批量刷整行/整列
openpyxl 没有“样式模板应用到 DataFrame 区域”的快捷方法。所有样式(字体加粗、背景色、居中、边框)都得循环单元格设置,效率低但可控。
立即学习“Python免费学习笔记(深入)”;
- 合并后的表头单元格(如
A1)建议设alignment=Alignment(horizontal='center', vertical='center')和font=Font(bold=True) - 数据区域首行(字段名行)通常设浅灰背景:
PatternFill('solid', fgColor='D3D3D3') - 边框推荐用
Side(border_style='thin')+Border组合,避免用'medium'导致 Excel 打开报错 - 不要尝试给整列设样式(如
ws.column_dimensions['A'].width = 20可以,但ws.column_dimensions['A'].font = ...无效)
导出前务必调用 writer.close(),否则文件损坏
这是最常被忽略的操作。不调用 close(),openpyxl 缓存未刷新,生成的 .xlsx 文件打不开,或打开后提示“发现不可读内容”,点修复后样式全丢、合并单元格消失。
典型错误写法:with pd.ExcelWriter(...) as writer: —— 这看似自动关闭,但若中途抛异常(比如合并单元格坐标越界),__exit__ 可能没执行完;更稳妥的是显式 try/finally 或确保 close() 在最后无条件执行。
复杂点在于:多表头+样式逻辑一旦写错(比如合并了不存在的区域 A1:Z1000),openpyxl 不会立刻报错,而是等到 close() 时才崩溃,错误信息晦涩(如 KeyError: 'styles')。建议先注释掉样式代码,验证表头合并是否成功,再逐步加样式。


















