
处理Excel这件事我踩过的坑加起来能写一本书。
最早用VBA,后来学了Python觉得自己升华了,结果发现Python生态里处理Excel的库有好几个,每次选错就是半天白费。
今天把三个最常用的库彻底对比一遍,openpyxl、pandas、xlwings,每个都说清楚:适合干嘛、不适合干嘛、哪些坑是我替你踩过的。
往期阅读>>>
Python 自动化管理Jenkins的15个实用脚本,提升效率
App2Docker:如何无需编写Dockerfile也可以创建容器镜像
Python 自动化识别Nginx配置并导出为excel文件,提升Nginx管理效率
不想看完整文章的,直接看这段:
openpyxl:你要操作Excel格式(合并单元格、设置样式、写公式),用这个
pandas:你要做数据分析、大批量读写、数据清洗,用这个
xlwings:你要跟已经打开的Excel文件交互、执行VBA,用这个
用错了不是不能跑,是你会很痛苦。
openpyxl直接操作.xlsx文件,不需要本机装Excel,读写改样式都行。
fromopenpyxlimportWorkbookfromopenpyxl.stylesimportFont, PatternFill, Alignmentfromopenpyxl.utilsimportget_column_letterwb = Workbook()ws = wb.activews.title = "月度报表"# 写标题行headers = ["姓名", "部门", "销售额", "完成率"]forcol_num, headerinenumerate(headers, 1):cell = ws.cell(row=1, column=col_num, value=header)cell.font = Font(bold=True, color="FFFFFF")cell.fill = PatternFill(start_color="2F75B6", end_color="2F75B6", fill_type="solid")cell.alignment = Alignment(horizontal="center")# 写数据data = [ ("张三", "销售部", 120000, "120%"), ("李四", "销售部", 95000, "95%"), ("王五", "市场部", 88000, "88%"),]forrow_dataindata:ws.append(row_data)# 设置列宽fori, colinenumerate(ws.columns):ws.column_dimensions[get_column_letter(i+1)].width = 15wb.save("月度报表.xlsx")
坑一:合并单元格之后写不进去数据
第一次遇到这个坑的时候搞了大半天。合并之后只有左上角的单元格能写值,其他位置写了也是白写。
ws.merge_cells("A1:D1")ws["A1"] = "Q1季度总结"# 只能写A1# ws["B1"] = "什么" 写了也没用,保存之后还是空的
坑二:写公式不等于有计算结果
ws["E2"] = "=SUM(A2:D2)"# 公式写进去了# 但用openpyxl读这个文件,读出来是字符串 "=SUM(A2:D2)"# 不是计算结果
想读公式结果要么打开Excel让它重新计算,要么用xlwings——后面说。
坑三:几万行以上写得很慢
超过几万行的Excel,openpyxl写起来开始掉速,这种情况换pandas。
pandas才不管你单元格什么颜色,它就管数据。读取、过滤、聚合、处理、输出,这套流程用它是最顺的。
importpandasaspddf = pd.read_excel("销售数据.xlsx", sheet_name="Sheet1")df_clean = (df .dropna(subset=["销售额"]) .query("销售额 > 0") .assign(完成率=lambdax: x["销售额"] /x["目标额"]) .sort_values("销售额", ascending=False))summary = df_clean.groupby("部门").agg(总销售额=("销售额", "sum"),平均完成率=("完成率", "mean"),人数=("姓名", "count")).reset_index()print(summary)
同时处理多个sheet:
all_sheets = pd.read_excel("数据.xlsx", sheet_name=None)combined = pd.concat(all_sheets.values(), ignore_index=True)
写出带格式的Excel(搭xlsxwriter):
withpd.ExcelWriter("报告.xlsx", engine="xlsxwriter") aswriter:df.to_excel(writer, sheet_name="数据", index=False)workbook = writer.bookworksheet = writer.sheets["数据"]header_fmt = workbook.add_format({"bold": True,"bg_color": "#2F75B6","font_color": "white","align": "center", })forcol_num, valueinenumerate(df.columns.values):worksheet.write(0, col_num, value, header_fmt)
坑一:日期列变成 Timestamp 了
df = pd.read_excel("数据.xlsx")print(df["日期"][0]) # 2024-01-15 00:00:00,不是你想要的格式# 转成字符串df["日期"] = df["日期"].dt.strftime("%Y-%m-%d")
坑二:金额列浮点精度掉了
钱相关的计算不能直接用float,0.1+0.2不等于0.3,这不是Python的问题,是所有语言的浮点数问题:
fromdecimalimportDecimaldf["金额"] = df["金额"].apply(lambdax: Decimal(str(x)))
坑三:大文件内存不够用
500MB以上的Excel直接read_excel会把整个文件塞进内存,小内存机器很容易OOM。pandas不支持分块读Excel,超大文件建议先转CSV:
chunk_size = 10000forchunkinpd.read_csv("大文件.csv", chunksize=chunk_size):process(chunk)
xlwings需要本机装Excel,它直接操控Excel进程。
能做:
读已打开文件的实时数据
读公式计算结果(不是公式字符串)
执行VBA宏
生成图表截图
importxlwingsasxwwb = xw.Book("报表.xlsx")ws = wb.sheets["Sheet1"]# 读取值(公式结果,不是公式本身)value = ws["B2"].value# 批量读取data = ws.range("A1:D10").value# 返回二维列表# 调用VBA宏app = xw.apps.activeapp.macro("ThisWorkbook.刷新数据")()# 把Python处理结果写回ws["A1"].value = [[1, 2, 3], [4, 5, 6]]
用完自动关闭进程:
withxw.App(visible=False) asapp:wb = app.books.open("报表.xlsx")ws = wb.sheets[0]ws["A1"].value = "处理完成"wb.save()wb.close()# 出了with块自动关闭Excel进程
坑一:以为脚本跑完了Excel就关了
没显式关的话Excel进程会一直挂后台,下次再跑同一文件直接报“文件已被占用”。一定要用with语法或者手动close。
坑二:macOS权限问题
macOS用xlwings要给Python授权“辅助功能”权限,不然报:
appscript.reference.CommandError: errAEEventNotPermitted(-1743)去系统偏好设置 > 隐私与安全性 > 辅助功能,把Terminal或IDE加进去。
坑三:服务器上跑不了
Linux没有Excel,xlwings在上面没法用。定时任务、Docker容器里处理Excel,只能用openpyxl或pandas。
| 场景 | 用哪个 |
|---|---|
| 纯读写,不管格式 | pandas |
| 设置样式、合并单元格 | openpyxl |
| 数据分析聚合统计 | pandas |
| 读公式计算结果 | xlwings |
| 执行VBA宏 | xlwings |
| 服务器定时任务 | openpyxl / pandas |
| 百万行以上超大文件 | pandas |
很多项目不是单用一个的。比如每周生成带格式的销售报表这种需求:
importpandasaspdfromopenpyxlimportload_workbookfromopenpyxl.stylesimportFont, PatternFill# pandas 处理数据df_raw = pd.read_excel("原始数据.xlsx")df_result = df_raw.groupby("部门").agg({"销售额": "sum"}).reset_index()# pandas 先写出基础Exceldf_result.to_excel("报表.xlsx", index=False)# openpyxl 再美化wb = load_workbook("报表.xlsx")ws = wb.activeforcellinws[1]:cell.font = Font(bold=True, color="FFFFFF")cell.fill = PatternFill(start_color="2F75B6", end_color="2F75B6", fill_type="solid")wb.save("报表_最终.xlsx")
pandas负责数据,openpyxl负责样式。各干各的事,代码也清晰。
三个库不是谁比谁强,就是用途不一样:
openpyxl - 要格式要样式,找它
pandas - 要处理分析数据,找它
xlwings - 要操控Excel本体读公式结果,找它
选错了不是实现不了,是实现起来会很绕。我之前试过用openpyxl读公式结果,搞了两个小时才发现根本就不是这个库该做的事。
你在项目里处理Excel遇到过什么奇葩问题吗?评论区聊聊。
https://ima.qq.com/wiki/?shareId=f2628818f0874da17b71ffa0e5e8408114e7dbad46f1745bbd1cc1365277631c
