
处理Excel这件事我踩过的坑加起来能写一本书。
最早用VBA,后来学了Python觉得自己升华了,结果发现Python生态里处理Excel的库有好几个,每次选错就是半天白费。
今天把三个最常用的库彻底对比一遍,openpyxl、pandas、xlwings,每个都说清楚:适合干嘛、不适合干嘛、哪些坑是我替你踩过的。
不想看完整文章的,直接看这段:
用错了不是不能跑,是你会很痛苦。
openpyxl直接操作.xlsx文件,不需要本机装Excel,读写改样式都行。
fromopenpyxlimportWorkbook
fromopenpyxl.stylesimportFont, PatternFill, Alignment
fromopenpyxl.utilsimportget_column_letter
wb = Workbook()
ws = wb.active
ws.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 = 15
wb.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才不管你单元格什么颜色,它就管数据。读取、过滤、聚合、处理、输出,这套流程用它是最顺的。
importpandasaspd
df = 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.book
worksheet = 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的问题,是所有语言的浮点数问题:
fromdecimalimportDecimal
df["金额"] = df["金额"].apply(lambdax: Decimal(str(x)))坑三:大文件内存不够用
500MB以上的Excel直接read_excel会把整个文件塞进内存,小内存机器很容易OOM。pandas不支持分块读Excel,超大文件建议先转CSV:
chunk_size = 10000
forchunkinpd.read_csv("大文件.csv", chunksize=chunk_size):
process(chunk)xlwings需要本机装Excel,它直接操控Excel进程。
能做:
importxlwingsasxw
wb = xw.Book("报表.xlsx")
ws = wb.sheets["Sheet1"]
# 读取值(公式结果,不是公式本身)
value = ws["B2"].value
# 批量读取
data = ws.range("A1:D10").value # 返回二维列表
# 调用VBA宏
app = xw.apps.active
app.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 |
很多项目不是单用一个的。比如每周生成带格式的销售报表这种需求:
importpandasaspd
fromopenpyxlimportload_workbook
fromopenpyxl.stylesimportFont, PatternFill
# pandas 处理数据
df_raw = pd.read_excel("原始数据.xlsx")
df_result = df_raw.groupby("部门").agg({"销售额": "sum"}).reset_index()
# pandas 先写出基础Excel
df_result.to_excel("报表.xlsx", index=False)
# openpyxl 再美化
wb = load_workbook("报表.xlsx")
ws = wb.active
forcellinws[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遇到过什么奇葩问题吗?评论区聊聊。
“无他,惟手熟尔”!有需要的用起来!
本文分享自 Nicholas与Pypi 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!