日常处理数据时,很多朋友第一时间会想到用 Pandas 或者 openpyxl。它们确实很强大,但在实际工作场景中,我们经常会遇到一些让人头疼的问题:Pandas 读写 Excel 经常会把原有的单元格格式、公式甚至图表全搞丢;openpyxl 虽然能保留部分格式,但操作起来略显繁琐,而且无法实时看到 Excel 的变化。
请在微信客户端打开
这时候,就需要今天的主角登场了——xlwings。
和传统的库不同,xlwings 是通过调用系统底层的 COM 组件(Windows)或 AppleScript(Mac)来直接“遥控” Excel 应用程序的。这意味着,你在 Excel 里能手动做的事情,xlwings 基本都能用 Python 跑着做,而且完美保留所有原汁原味的格式。
废话不多说,我们先来看看它的工作原理,然后直接上代码实战。
xlwings 是如何工作的?
理解 xlwings 的层级结构,写代码就不会迷路。它的控制逻辑是从大到小,层层递进的。以下是它的核心流转过程:
graph TDA[Python 脚本] -->|驱动| B(xlwings 引擎)B -->|建立连接| C{Excel 应用程序 App}C -->|管理| D[工作簿 Workbook]D -->|操作| E[工作表 Sheet]E -->|读写| F[单元格 Range]
正如流程图所示,我们要操作一个单元格,首先要唤醒 Excel 程序,然后打开工作簿,选定工作表,最后才是操作具体的范围。
实战代码一:基础读写与隐式操作
很多时候我们希望程序在后台默默干活,不要弹出 Excel 界面打扰我们。下面这段代码展示了如何隐蔽地打开一个包含多站点数据的表格,并写入和读取数据。
假设我们正在处理 2023 到 2024 年的卫星遥感数据。
import xlwings as xw# visible=False 表示不要显示Excel界面,在后台默默运行# add_book=False 表示不要一上来就自动新建一个空白工作簿app = xw.App(visible=False, add_book=False)# 打开我们已经存在的本地文件wb = app.books.open('GF3_Data_2023_2024.xlsx')# 选中名为 "Bayan Nur" (巴彦淖尔) 的工作表sheet = wb.sheets['Bayan Nur']# 批量写入表头sheet.range('A1').value = ['站点名称', '获取日期', '后向散射系数', '实测土壤水分', '反演RMSE']# 写入一行具体的业务数据sheet.range('A2').value = ['巴彦淖尔站点_01', '2024-05-12', -12.5, 0.18, 0.035]# 将刚才写入的数据读取出来,放入一个列表中# options(ndim=2) 确保读取出来的是二维列表,方便后续处理data = sheet.range('A1:E2').options(ndim=2).valueprint("后台读取到的数据如下:")for row in data:print(row)# 养成良好习惯,保存并关闭文件,最后退出Excel程序wb.save()wb.close()app.quit()
实战代码二:多工作表批量处理与格式修改
如果是跨多个 Sheet 进行批量检查,xlwings 的优势就体现出来了。比如我们有一个汇总了 27 个站点数据的 Excel 文件,现在需要批量检查所有大安(Da'an)、吐鲁番(Turpan)等站点的数据,把误差过大的数值高亮显示出来。
import xlwings as xw# 这一次我们让可见,方便看着程序自动处理app = xw.App(visible=True, add_book=False)wb = app.books.open('Station_Data_Summary.xlsx')# 遍历工作簿中的所有工作表for sheet in wb.sheets:# 动态获取当前工作表中有数据的最后一行# 相当于在Excel里按 Ctrl + 向上箭头last_row = sheet.range('A' + str(sheet.cells.last_cell.row)).end('up').row# 假设均方根误差 (RMSE) 数据记录在 E 列# 从第二行开始遍历(跳过表头)for i in range(2, last_row + 1):rmse_cell = sheet.range(f'E{i}')# 提取值进行逻辑判断if rmse_cell.value is not None and rmse_cell.value > 0.05:# 发现误差大于0.05的异常值,修改单元格背景色为红色 (RGB值)rmse_cell.color = (255, 100, 100)# 调用原生的 api 将字体加粗,极其方便rmse_cell.api.Font.Bold = True# 另存为新文件,避免覆盖原始数据wb.save('Station_Data_Summary_Checked.xlsx')wb.close()app.quit()
实战代码三:打通 Pandas 与 Matplotlib 画图模块
这也是 xlwings 最吸引人的功能之一。它可以直接接收 Pandas 的 DataFrame,甚至可以把你用 Matplotlib 画好的图表,原封不动地贴到 Excel 里面去,做自动化报告非常顺手。
import xlwings as xwimport pandas as pdimport matplotlib.pyplot as plt# 随便准备一点时间序列数据df = pd.DataFrame({'观测月份': ['4月', '5月', '6月', '7月', '8月'],'平均地表粗糙度': [1.2, 1.5, 1.3, 1.4, 1.1]})# 用 Matplotlib 画一个简单的趋势折线图fig = plt.figure(figsize=(7, 4))plt.plot(df['观测月份'], df['平均地表粗糙度'], marker='o', color='b')plt.title('2024年春夏地表参数变化趋势')plt.ylabel('Roughness Parameter')plt.grid(True)# 启动 Excel 并新建一个工作簿app = xw.App(visible=True, add_book=True)wb = app.books[0]sht = wb.sheets[0]# 一键把 DataFrame 写进 Excel# options(index=False) 意思是不要把 Pandas 默认的 0,1,2,3 索引写进去sht.range('A1').options(index=False).value = df# 一键把刚才画的图表插入到 Excel 中# 设定图片左上角对齐到 D1 单元格,完美排版sht.pictures.add(fig, name='Trend_Chart', update=True, left=sht.range('D1').left, top=sht.range('D1').top)# 留着界面不关闭,方便大家直观感受效果# 实际生产环境中记得加上 wb.save() 和 app.quit()
总结
其实 xlwings 的功能远不止于此,它甚至支持用 Python 来替代复杂的 VBA 宏,也就是直接在 Excel 里面写自定义函数(UDF),让 Excel 里的公式直接调用你写好的 Python 代码。
如果你平时的业务涉及到大量带格式的模板填充、多表数据清洗汇总,或者需要生成带图表的自动化报告,强烈建议把 xlwings 纳入你的工具箱,它绝对能帮你省下大把的加班时间。

夜雨聆风