🔥
个人主页:
杨利杰YJlio
❄️
个人专栏:
《Sysinternals实战教程》
《Windows PowerShell 实战》
《WINDOWS教程》
《IOS教程》
《微信助手》
《锤子助手》
《Python》
《Kali Linux》
《那些年未解决的Windows疑难杂症》
🌟
让复杂的事情更简单,让重复的工作自动化

《超简单:用 Python 让 Excel 飞起来》读书笔记:3.7.1 xlwings 模块与 pandas 模块的交互
- 1. 3.7.1 xlwings 模块与 pandas 模块的交互
- 2. 为什么要把 pandas 和 xlwings 放在一起用
- 3. 环境准备:pandas、xlwings、openpyxl 分别负责什么
- 4. pandas 造表:先构造一张工资报表示例
- 5. xlwings 写入 Excel:最关键的一行代码
- 6. 完整代码:pandas 生成 DataFrame,再用 xlwings 写入 Excel
- 7. 关键代码拆解:打开、新建、清空、写入、保存
- 8. 自动化闭环:不要忘记保存和关闭 Excel
- 9. 效果验证:不要只看代码有没有报错
- 10. 常见问题和踩坑提醒
- 11. 总结提升

1. 3.7.1 xlwings 模块与 pandas 模块的交互
V4修正版进度标记:本篇为 06月17日 第1篇,承接 06月07日第2篇“2.7.2 自定义函数”之后继续更新。
这一篇是我阅读《超简单:用 Python 让 Excel 飞起来》时整理的读书笔记,对应书籍中的 第3章 Python模块 / 3.7.1 xlwings 模块与 pandas 模块的交互。前面已经分别学习了 pandas 和 xlwings,但如果只把它们分开看,还是不够接近真实办公自动化场景。
在实际工作中,pandas 更适合做数据处理,比如造表、筛选、排序、计算、生成新列;xlwings 更适合控制本机 Excel,比如打开工作簿、选择工作表、写入单元格、调整列宽、保存文件。二者组合起来,才是比较完整的 Excel 自动化链路。
我把这一节的核心理解成一句话:pandas 负责把数据算好,xlwings 负责把结果写进 Excel 并完成落地。
这不是两个模块简单叠加,而是职责分工:pandas 管数据,xlwings 管 Excel。
这张图展示的是 pandas 与 xlwings 的整体交互关系。左侧是 pandas 生成 DataFrame,中间通过 xlwings 传递,右侧把结果写入 Excel 工作簿。

从图中可以看出,pandas 和 xlwings 并不是互相替代的关系。pandas 的优势在数据处理,xlwings 的优势在操作 Excel 应用。办公自动化真正稳定的写法,通常是先用 pandas 生成干净的数据结果,再交给 xlwings 写入指定工作表。

2. 为什么要把 pandas 和 xlwings 放在一起用
单独使用 pandas,可以很方便地读取、清洗、计算和导出表格。但它对 Excel 窗口本身的控制能力有限,比如你想打开已有工作簿、选择某个工作表、清空区域、写入结果并调整列宽,这些动作就不如 xlwings 直观。
单独使用 xlwings,也可以直接往 Excel 单元格里写内容。但如果涉及大量数据处理,比如筛选部门、计算工资、生成统计列、处理空值,纯靠 xlwings 一格一格操作会很啰嗦,效率也不高。
所以二者组合的意义很明确:pandas 先把表格数据处理成最终结果,xlwings 再把这个结果写入 Excel,并负责保存和关闭。
推荐理解方式:pandas 是数据加工车间,xlwings 是 Excel 交付通道。
不要把职责搞反。如果用 xlwings 做大量数据筛选计算,脚本会变重;如果只用 pandas 而需要精细控制 Excel 界面和工作簿对象,又会不够灵活。
#mermaid-svg-J432kN92Fsaw5YJ4{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-J432kN92Fsaw5YJ4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-J432kN92Fsaw5YJ4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-J432kN92Fsaw5YJ4 .error-icon{fill:#552222;}#mermaid-svg-J432kN92Fsaw5YJ4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-J432kN92Fsaw5YJ4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-J432kN92Fsaw5YJ4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-J432kN92Fsaw5YJ4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-J432kN92Fsaw5YJ4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-J432kN92Fsaw5YJ4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-J432kN92Fsaw5YJ4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-J432kN92Fsaw5YJ4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-J432kN92Fsaw5YJ4 .marker.cross{stroke:#333333;}#mermaid-svg-J432kN92Fsaw5YJ4 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-J432kN92Fsaw5YJ4 p{margin:0;}#mermaid-svg-J432kN92Fsaw5YJ4 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-J432kN92Fsaw5YJ4 .cluster-label text{fill:#333;}#mermaid-svg-J432kN92Fsaw5YJ4 .cluster-label span{color:#333;}#mermaid-svg-J432kN92Fsaw5YJ4 .cluster-label span p{background-color:transparent;}#mermaid-svg-J432kN92Fsaw5YJ4 .label text,#mermaid-svg-J432kN92Fsaw5YJ4 span{fill:#333;color:#333;}#mermaid-svg-J432kN92Fsaw5YJ4 .node rect,#mermaid-svg-J432kN92Fsaw5YJ4 .node circle,#mermaid-svg-J432kN92Fsaw5YJ4 .node ellipse,#mermaid-svg-J432kN92Fsaw5YJ4 .node polygon,#mermaid-svg-J432kN92Fsaw5YJ4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-J432kN92Fsaw5YJ4 .rough-node .label text,#mermaid-svg-J432kN92Fsaw5YJ4 .node .label text,#mermaid-svg-J432kN92Fsaw5YJ4 .image-shape .label,#mermaid-svg-J432kN92Fsaw5YJ4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-J432kN92Fsaw5YJ4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-J432kN92Fsaw5YJ4 .rough-node .label,#mermaid-svg-J432kN92Fsaw5YJ4 .node .label,#mermaid-svg-J432kN92Fsaw5YJ4 .image-shape .label,#mermaid-svg-J432kN92Fsaw5YJ4 .icon-shape .label{text-align:center;}#mermaid-svg-J432kN92Fsaw5YJ4 .node.clickable{cursor:pointer;}#mermaid-svg-J432kN92Fsaw5YJ4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-J432kN92Fsaw5YJ4 .arrowheadPath{fill:#333333;}#mermaid-svg-J432kN92Fsaw5YJ4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-J432kN92Fsaw5YJ4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-J432kN92Fsaw5YJ4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-J432kN92Fsaw5YJ4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-J432kN92Fsaw5YJ4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-J432kN92Fsaw5YJ4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-J432kN92Fsaw5YJ4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-J432kN92Fsaw5YJ4 .cluster text{fill:#333;}#mermaid-svg-J432kN92Fsaw5YJ4 .cluster span{color:#333;}#mermaid-svg-J432kN92Fsaw5YJ4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-J432kN92Fsaw5YJ4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-J432kN92Fsaw5YJ4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-J432kN92Fsaw5YJ4 .icon-shape,#mermaid-svg-J432kN92Fsaw5YJ4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-J432kN92Fsaw5YJ4 .icon-shape p,#mermaid-svg-J432kN92Fsaw5YJ4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-J432kN92Fsaw5YJ4 .icon-shape .label rect,#mermaid-svg-J432kN92Fsaw5YJ4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-J432kN92Fsaw5YJ4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-J432kN92Fsaw5YJ4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-J432kN92Fsaw5YJ4 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
原始数据 / 模拟数据
pandas 构造 DataFrame
pandas 清洗 / 计算 / 新增列
xlwings 打开或新建 Excel
选择或创建工作表
写入 DataFrame
调整列宽 / 保存 / 关闭
这个流程图可以把本文的主线讲清楚:先在 Python 里把数据算好,再通过 Excel 自动化完成交付。这样写出来的脚本更容易维护,也更符合真实办公自动化的处理习惯。

3. 环境准备:pandas、xlwings、openpyxl 分别负责什么
开始写代码前,先把环境准备好。本文用到三个常见模块:pandas、xlwings 和 openpyxl。安装命令如下:
pip install pandas xlwings openpyxl
pandas 主要负责构造和处理 DataFrame;xlwings 主要负责操作本机 Excel 应用;openpyxl 常用于 Excel 文件读写引擎,装上以后很多 Excel 读写场景会更稳。
这张图展示的是环境准备与核心流程。左侧列出了 pandas、xlwings、openpyxl 的模块分工,右侧展示从构造 DataFrame 到保存退出 Excel 的五步链路。

从图中可以看出,环境准备不是简单装几个包,而是要知道每个包在链路中承担什么角色。pandas 是数据处理核心,xlwings 是 Excel 控制核心,openpyxl 则更多是文件读写场景中的辅助依赖。
常见问题:如果 pip install 显示安装成功,但运行脚本仍然提示找不到模块,大概率是当前运行脚本的 Python 解释器和安装模块的 Python 环境不是同一个。
可以先用下面的代码做最小验证:
import pandas as pd
import xlwings as xw
print("pandas 和 xlwings 导入成功")
推荐做法:正式写自动化脚本前,先单独确认模块能导入,再继续写业务逻辑。不要把环境问题和代码问题混在一起排查。

4. pandas 造表:先构造一张工资报表示例
这一节先不用读取真实 Excel 文件,而是直接用 pandas 构造一张示例工资报表。这样做的好处是排除文件路径、文件占用、表头不一致等干扰,先把 pandas → xlwings → Excel 这条链路跑通。
示例数据包括工号、姓名、部门、月薪,并新增一列“涨薪后月薪”。代码如下:
import pandas as pd
df = pd.DataFrame({
"工号": ["E001", "E002", "E003"],
"姓名": ["张三", "李四", "王五"],
"部门": ["IT", "HR", "财务"],
"月薪": [8000, 7500, 9000],
})
df["涨薪后月薪"] = (df["月薪"] * 1.1).round(0).astype(int)
print(df)
这里的关键点不是数据有多复杂,而是 pandas 可以像 Excel 公式一样生成新列。df["月薪"] * 1.1 表示对整列月薪统一乘以 1.1,round(0) 表示四舍五入到整数,astype(int) 表示转换为整数类型。
这张图展示的是 pandas 构造工资报表并新增计算列的过程。表格中包含工号、姓名、部门、月薪、涨薪后月薪,重点突出 DataFrame 的计算能力。

从图中可以看出,pandas 不只是保存数据,它还能直接生成报表结果。也就是说,等数据交给 xlwings 之前,DataFrame 里已经是处理后的结果,而不是一堆还需要人工二次加工的原始数据。
这里的本质是:用 pandas 在 Python 里提前完成 Excel 公式计算。
推荐做法:正式处理真实报表前,先用这种小型模拟数据验证逻辑,确认计算列结果正确后,再替换成真实数据源。

5. xlwings 写入 Excel:最关键的一行代码
当 DataFrame 已经构造完成后,接下来就是把它写入 Excel。xlwings 支持直接把 DataFrame 写到某个单元格起始位置,最关键的一行代码是:
sht.range("A1").value = df
这行代码的含义很直接:把 df 这个 DataFrame 从当前工作表的 A1 单元格开始写入。默认情况下,它会把列名作为表头一起写进去,下面继续写入数据内容。
这张图展示的是 xlwings 将 DataFrame 写入 Excel 的效果。左侧是 Python 代码,核心语句是 sht.range('A1').value = df,右侧展示 Excel 中从 A1 开始写入后的表格结果。

从图中可以看出,xlwings 写入 DataFrame 时不是一格一格手动赋值,而是直接把整张表写进去。这也是 pandas 和 xlwings 配合最舒服的地方:pandas 生成表,xlwings 一次性写表。
一句话记忆:sht.range(“A1”).value = df 就是 pandas 到 Excel 的黄金通道。
如果希望从其他位置开始写入,也可以改起始单元格。例如写到 B2:
sht.range("B2").value = df
注意:写入起始位置不同,会影响表头和数据落点。如果后续还有固定模板、标题行或说明文字,需要提前规划好起始单元格。

6. 完整代码:pandas 生成 DataFrame,再用 xlwings 写入 Excel
前面已经拆开讲了 pandas 造表和 xlwings 写表。下面把它们合成一个完整脚本。这个版本适合作为入门模板:先生成工资报表,再写入指定 Excel 文件。
# -*- coding: utf-8 -*-
"""
文件名:3.7.1 xlwings模块与pandas模块的交互.py
功能:pandas 生成 DataFrame,并通过 xlwings 写入 Excel
"""
import os
import pandas as pd
import xlwings as xw
def build_dataframe() –> pd.DataFrame:
"""用 pandas 构造一张示例报表"""
df = pd.DataFrame({
"工号": ["E001", "E002", "E003"],
"姓名": ["张三", "李四", "王五"],
"部门": ["IT", "HR", "财务"],
"月薪": [8000, 7500, 9000],
})
# 示例:生成新列,涨薪 10%
df["涨薪后月薪"] = (df["月薪"] * 1.1).round(0).astype(int)
return df
def write_df_to_excel(df: pd.DataFrame, output_path: str, sheet_name: str = "汇总"):
"""
使用 xlwings 将 DataFrame 写入 Excel
参数说明:
df : 要写入 Excel 的 DataFrame
output_path : 输出文件路径,不存在就新建
sheet_name : 写入的工作表名称
"""
app = xw.App(visible=False, add_book=False)
wb = None
try:
# 1. 打开已有文件,或新建工作簿
if os.path.exists(output_path):
wb = app.books.open(output_path)
else:
wb = app.books.add()
wb.save(output_path)
# 2. 获取或创建工作表
sheet_names = [s.name for s in wb.sheets]
if sheet_name in sheet_names:
sht = wb.sheets[sheet_name]
else:
sht = wb.sheets.add(sheet_name)
# 3. 清空旧内容,避免历史数据残留
sht.clear()
# 4. 从 A1 开始写入 DataFrame
sht.range("A1").value = df
# 5. 自动调整列宽,让报表更易读
sht.autofit()
# 6. 保存并关闭
wb.save()
wb.close()
print(f"已写入成功:{output_path} -> [{sheet_name}]")
finally:
if wb is not None:
try:
wb.close()
except Exception:
pass
app.quit()
if __name__ == "__main__":
# 1. pandas 造表
df_report = build_dataframe()
# 2. xlwings 写入 Excel
out_file = r"C:\\Temp\\output\\3.7.1_xlwings_pandas_交互示例.xlsx"
write_df_to_excel(df_report, out_file, sheet_name="汇总")
这段代码分成两个函数。build_dataframe() 只负责构造数据,不碰 Excel;write_df_to_excel() 只负责把数据写入 Excel,不负责业务计算。这样拆分以后,代码结构更清楚,后续替换数据源或修改输出逻辑也更方便。
推荐做法:把“数据处理”和“Excel 写入”拆成两个函数,不要全部堆在一个主流程里。
现场注意:如果输出目录 C:\\Temp\\output 不存在,可能会保存失败。真实脚本建议先判断并创建目录。
可以在写入前补一段目录创建逻辑:
out_dir = os.path.dirname(output_path)
if out_dir and not os.path.exists(out_dir):
os.makedirs(out_dir)

7. 关键代码拆解:打开、新建、清空、写入、保存
完整代码看起来不长,但里面有几个关键动作必须理解,否则后面改成真实业务脚本时很容易出问题。
第一步是启动 Excel 应用:
app = xw.App(visible=False, add_book=False)
visible=False 表示不显示 Excel 窗口,更适合自动化跑批;add_book=False 表示启动 Excel 时不要自动创建空白工作簿,避免多余对象干扰。
第二步是判断输出文件是否存在:
if os.path.exists(output_path):
wb = app.books.open(output_path)
else:
wb = app.books.add()
wb.save(output_path)
如果文件存在,就打开已有文件;如果不存在,就新建工作簿并保存到目标路径。这样脚本既能首次生成文件,也能后续重复更新。
第三步是获取或创建工作表:
sheet_names = [s.name for s in wb.sheets]
if sheet_name in sheet_names:
sht = wb.sheets[sheet_name]
else:
sht = wb.sheets.add(sheet_name)
这一步很实用。因为真实办公文件里,工作表可能已经存在,也可能还没有。脚本不能假设它一定存在,否则会在不同机器或不同文件上运行不稳定。
第四步是清空旧内容:
sht.clear()
这一步看似简单,但非常关键。如果旧报表有 100 行,新报表只有 80 行,不清空旧内容,就可能出现后 20 行历史数据残留,造成报表脏数据。
这是重复生成报表时很常见的坑:新数据写进去了,但旧数据没有清掉,最后报表看起来像对的,实际上夹杂了历史内容。
第五步是写入和排版:
sht.range("A1").value = df
sht.autofit()
sht.range("A1").value = df 负责写表,sht.autofit() 负责自动调整列宽。虽然 autofit() 不是必须的,但它能让输出文件打开后更像一张可读报表。

8. 自动化闭环:不要忘记保存和关闭 Excel
xlwings 和纯文件读写库不同,它会真正调用本机 Excel 进程。因此,只要脚本启动了 Excel,就必须考虑什么时候保存、什么时候关闭工作簿、什么时候退出应用。
正确的闭环通常包括:
wb.save()
wb.close()
app.quit()
wb.save() 表示保存工作簿;wb.close() 表示关闭工作簿;app.quit() 表示退出 Excel 应用。三者不是一回事,不能混为一谈。
这张图展示的是 Excel 自动化闭环:新建或打开工作簿、获取或创建工作表、清空旧内容、写入 DataFrame、自动列宽、保存并关闭 Excel,同时提醒不要忘记关闭 Excel 进程。

从图中可以看出,写入数据只是中间动作,真正完整的自动化流程还必须包含保存和关闭。如果脚本只写入不保存,结果可能没有落盘;如果只保存不关闭,Excel 进程可能残留;如果异常时没有执行 app.quit(),后台可能堆积多个 EXCEL.EXE。
风险提醒:写 xlwings 脚本时,一定要把 app.quit() 放进兜底逻辑里。否则脚本跑多了,Excel 后台进程会越积越多。
推荐做法:使用 try…finally 结构,确保即使中途报错,也能尽量关闭 Excel 应用。
app = xw.App(visible=False, add_book=False)
try:
# 这里写 Excel 处理逻辑
pass
finally:
app.quit()

9. 效果验证:不要只看代码有没有报错
这一类脚本不能只用“没有报错”来判断成功。因为没有报错只说明 Python 执行流程走完了,不代表 Excel 文件内容一定符合预期。
我建议至少检查四个点:第一,目标文件是否生成;第二,工作表名称是否正确;第三,从 A1 开始是否写入完整表头和数据;第四,Excel 后台进程是否正常退出。
验证重点:脚本输出成功提示只是第一层验证,打开 Excel 文件检查内容才是更可靠的验证。
可以在代码里增加简单的输出提示:
print("输出文件:", output_path)
print("工作表名称:", sheet_name)
print("写入行列:", df.shape)
print("写入列名:", df.columns.tolist())
如果输出结果类似下面这样,就能初步确认写入对象和数据规模:
输出文件: C:\\Temp\\output\\3.7.1_xlwings_pandas_交互示例.xlsx
工作表名称: 汇总
写入行列: (3, 5)
写入列名: ['工号', '姓名', '部门', '月薪', '涨薪后月薪']
真实工作里还建议打开输出文件确认:表头是否在第一行,中文是否正常,列宽是否合适,旧数据是否清空,涨薪后月薪是否符合计算预期。
推荐做法:自动化脚本第一次跑通后,先用小数据验证,再换真实业务数据。这样排错成本最低。
不要一上来就处理几万行真实文件。如果逻辑有错,错误会被放大,回头排查更麻烦。

10. 常见问题和踩坑提醒
第一个常见问题是:为什么脚本运行后没有看到 Excel 窗口?因为代码里使用了 visible=False。这是正常现象,表示 Excel 在后台运行。调试阶段可以临时改成 visible=True,这样更容易观察过程。
第二个常见问题是:为什么输出路径保存失败?通常是目标文件夹不存在,或者 Excel 文件正在被打开占用。路径不存在时,需要先创建目录;文件被占用时,需要先关闭对应 Excel 文件。
out_dir = os.path.dirname(output_path)
if out_dir and not os.path.exists(out_dir):
os.makedirs(out_dir)
第三个常见问题是:为什么旧数据还在?大概率是写入前没有清空工作表,或者只是覆盖了左上角区域,右侧和下方旧内容仍然残留。重复生成报表时,建议先执行 sht.clear()。
第四个常见问题是:为什么后台有很多 EXCEL.EXE?这通常是脚本异常退出后没有执行 app.quit(),或者中途报错后进程没有被释放。解决思路是使用 try…finally 兜底关闭。
这类问题不能只靠重启电脑解决。重启只是临时恢复,真正要改的是脚本结构,确保每次启动 Excel 后都有关闭动作。
第五个常见问题是:为什么中文列名或路径不稳定?一般建议脚本文件保存为 UTF-8,并尽量避免输出路径里夹杂特殊符号。中文路径通常可以正常使用,但在多环境部署时,英文路径更省心。
推荐脚本习惯:路径、工作表名称、输出文件名尽量集中写在主入口位置,不要散落在代码各处。
if __name__ == "__main__":
df_report = build_dataframe()
out_file = r"C:\\Temp\\output\\3.7.1_xlwings_pandas_交互示例.xlsx"
write_df_to_excel(df_report, out_file, sheet_name="汇总")

11. 总结提升
这一节的核心,是理解 pandas 和 xlwings 的协作方式。pandas 负责构造和处理 DataFrame,适合做清洗、计算、生成新列;xlwings 负责把结果写入 Excel,适合打开工作簿、选择工作表、清空内容、写入数据、调整列宽、保存关闭。
我把本文最关键的代码记成一句话:sht.range("A1").value = df。它是从 DataFrame 到 Excel 工作表的核心通道。但真正稳定的脚本,不只是这一行,还要包括路径处理、工作表判断、清空旧内容、保存文件和关闭 Excel 进程。
我的最终理解是:办公自动化不是单纯把数据写进 Excel,而是要形成“造表、写入、排版、保存、关闭”的完整闭环。
后续写类似脚本时,可以固定按“pandas 处理数据 → xlwings 打开 Excel → 获取 Sheet → 清空旧内容 → 写入 DataFrame → 自动列宽 → 保存关闭”的顺序设计。
真正需要警惕的地方是:脚本看似运行成功,但旧数据残留、文件未保存、Excel 进程未关闭。这些问题不会总是立刻报错,但会在后续批量处理时集中爆发。
我最后把本节压缩成一句话:**pandas 负责把数据算准,xlwings 负责把结果交付到 Excel;二者配合好,才是真正可复用的办公自动化脚本。**
返回顶部

