乐于分享
好东西不私藏

告别繁琐的VBA:用Python操控Excel的终极利器xlwings全解析

告别繁琐的VBA:用Python操控Excel的终极利器xlwings全解析

日常处理数据时,很多朋友第一时间会想到用 Pandas 或者 openpyxl。它们确实很强大,但在实际工作场景中,我们经常会遇到一些让人头疼的问题:Pandas 读写 Excel 经常会把原有的单元格格式、公式甚至图表全搞丢;openpyxl 虽然能保留部分格式,但操作起来略显繁琐,而且无法实时看到 Excel 的变化。

请在微信客户端打开

这时候,就需要今天的主角登场了——xlwings。

和传统的库不同,xlwings 是通过调用系统底层的 COM 组件(Windows)或 AppleScript(Mac)来直接“遥控” Excel 应用程序的。这意味着,你在 Excel 里能手动做的事情,xlwings 基本都能用 Python 跑着做,而且完美保留所有原汁原味的格式。

废话不多说,我们先来看看它的工作原理,然后直接上代码实战。

xlwings 是如何工作的?

理解 xlwings 的层级结构,写代码就不会迷路。它的控制逻辑是从大到小,层层递进的。以下是它的核心流转过程:

graph TD    A[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.50.180.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 = (255100100)            # 调用原生的 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.21.51.31.41.1]})# 用 Matplotlib 画一个简单的趋势折线图fig = plt.figure(figsize=(74))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 纳入你的工具箱,它绝对能帮你省下大把的加班时间。

编辑:余文彬
审校:余雨馨