pandas用openpyxl引擎的mode="a"仅支持追加新sheet或覆盖已有sheet;真正在已有sheet末尾追加数据,必须手动读取原sheet、计算最后一行、再逐单元格写入。

用 openpyxl 引擎配合 ExcelWriter 的 mode="a"
直接设 mode="a" 是最接近“追加”的方式,但 Pandas 本身不支持像文件那样追加写入新行——它只支持追加写入**新 sheet** 或**覆盖已有 sheet**。真正实现“在已有 sheet 末尾追加数据”,必须手动读取原 sheet、拼接、再写回。
-
mode="a"仅在引擎为openpyxl时有效;xlsxwriter不支持追加模式,会报错ValueError: Append mode is not supported with xlsxwriter - 即使用了
openpyxl,ExcelWriter(..., mode="a")默认也不会自动定位到最后一行;它只是打开文件并允许你写新 sheet,或用if_sheet_exists="overlay"(Pandas 1.4+)叠加内容,但叠加位置仍需手动控制 - 若目标 sheet 已存在且想追加数据,必须先用
openpyxl.load_workbook()读取,获取最大行号,再把DataFrame转成列表逐行写入
手动读取 + 定位最后一行 + 写入(推荐稳定方案)
这是唯一能确保数据追加到指定 sheet 末尾的可靠做法,尤其适用于日志类、采集类场景。关键不是靠 Pandas 自动推断,而是自己算好起始行。
- 用
openpyxl.load_workbook()打开文件,用ws.max_row获取当前最后一行(注意:空行也会计入,建议用ws.calculate_dimension()或遍历非空行校验) - 用
ws.append(...)只能追加在末尾,但无法控制列宽/格式;如需保留原格式(如日期列、数字格式),得用ws.cell(row=..., column=...).value = ...逐单元格赋值 -
DataFrame写入前建议调用df.values.tolist(),避免NaN写成None导致 openpyxl 报错;对时间类型,需转为datetime对象而非字符串
<pre class="brush:php;toolbar:false;">from openpyxl import load_workbook
import pandas as pd
<p>df = pd.DataFrame({"A": [1, 2], "B": ["x", "y"]})
wb = load_workbook("data.xlsx")
ws = wb["Sheet1"]
start_row = ws.max_row + 1</p><p>for r_idx, row in enumerate(df.values, start_row):
for c_idx, value in enumerate(row, 1):
ws.cell(row=r_idx, column=c_idx, value=value)</p><p>wb.save("data.xlsx")</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill6591" title="Li Python Sec Check"><img
src="https://img.php.cn/upload/skill/000/000/081/179102166033725.jpg" alt="Li Python Sec Check" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill6591" title="Li Python Sec Check" class="overflowclass">Li Python Sec Check</a>
<p class="overflowclass">Python 安全规范检查工具:基于 CloudBase 规范、腾讯安全指南,LLM 智能分析(默认禁用,优先本地执行)</p>
</div>
<a rel="nofollow" href="/xiazai/skill6591" title="Li Python Sec Check" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>用 if_sheet_exists="overlay"
配合 startrow(Pandas 1.4+)这个参数看似简化流程,但容易误以为“自动追加”,实际只是覆盖式写入——它不会帮你找最后一行,startrow 必须显式传入,否则默认从第 0 行开始,直接覆盖原数据。
- 必须提前知道目标 sheet 当前有多少行,否则无法安全设置
startrow;可结合pandas.read_excel(..., nrows=0)快速读表头+行数,但不读数据,性能尚可 -
if_sheet_exists="overlay"仅控制写入行为,不处理样式、合并单元格、公式等;原有格式会丢失 - 若原 sheet 有冻结窗格、筛选器等,写入后仍保留,但新增行不在筛选范围内,需手动刷新
为什么不用 to_csv + 合并?
CSV 追加简单(mode="a"),但 Excel 特性(多 sheet、格式、公式、图表)让它不可替代。强行用 CSV 中转再转 Excel,会丢失所有格式和结构信息,且 openpyxl 从 CSV 重写一遍反而更慢。
- 如果只是临时记录、无格式要求,CSV 确实更轻量;但只要涉及 Excel 原生能力(比如财务模板、带条件格式的报表),就必须直操作 Excel 文件
- 频繁追加小数据(如每分钟一条)时,反复打开/保存整个
.xlsx文件 I/O 开销大;此时应考虑缓存内存中的 DataFrame,定时批量写入
追加的本质不是“Pandas 功能”,而是“Excel 文件操作”。别指望 to_excel 自动猜你想要什么位置——它连 sheet 存不存在都要你明确说清楚。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










