Python + Excel自动化:从3小时到3秒的数据处理秘籍

刚开始接触Python处理Excel时,我以为就是读个文件、写个数据,结果连踩三个坑——读错编码、公式不更新、大型文件内存爆炸。今天就把这些血泪史摊开讲,顺便给你一套能直接用的代码。

先看第一个坑:为什么不用xlrd了?

老教程还在教你用xlrd.xlsx文件?这个库从2021年起就停止支持.xlsx了。我去年还因此写了半天代码,发现所有日期都变成了数字。那场面,像看天书。

>“

错误示范:读出来是数字

import xlrd
workbook = xlrd.open_workbook('报表.xlsx')

日期列返回的是Excel序列号 44197,而不是2021-01-01

`

正确姿势是用openpyxl(处理.xlsx)或pandas(通用方案)。我90%的场景都用pandas,因为它在数据处理上是真·亲爹级工具。

开篇示意图:一张对比图,左边是手动复制粘贴Excel的混乱工作流,右边是Python自动处理的清晰管道。

实战1:合并100个Excel文件,从3小时到3秒

上周帮财务部合并季度报表,100个销售团队的Excel文件,每个文件里的表格结构一模一样。手动做?Ctrl+C/V到手腕抽筋。用pandas:

`pyt

hon
import pandas as pd
import glob
import os

为什么要这么写:用glob匹配所有xlsx文件,比手动列文件名强100倍

file_paths = glob.glob('销售数据/*.xlsx')

创建空列表,别用.append一遍遍加DataFrame,那样内存会炸

dfs = []

for file in file_paths:
# 这里踩过坑:有些文件有隐藏sheet,用sheet_name明确指定
df = pd.read_excel(file, sheet_name='销售明细', engine='openpyxl')
# 加一列记录来源文件名,方便后面查问题
df['来源文件'] = os.path.basename(file)
dfs.append(df)

concat比append快5倍,尤其当数据量10万行以上时

combined_df = pd.concat(dfs, ignore_index=True)

输出到Excel,index=False是血的教训,不然你会多一列索引

combined_df.to_excel('合并报表.xlsx', index=False, engine='openpyxl')
`

运行时间对比:手动3小时 → 脚本3.2秒。财务妹子看到结果时,表情从“你在开玩笑?”变成了“这玩意儿能帮我写报销单吗?”

另一个坑:Excel公式不更新,数据永远是错的

有次我用openpyxl读取同事的报表,里面有些单元格是SUM公式。结果读出来全是None,我以为数据丢了,差点重做所有工作。

原因:openpyxl默认读取的是公式文本,不是计算结果。你要用data_only=True参数,但还有个更恶心的坑——如果公式依赖的文件没打开过,就算用了这个参数,读出来的还是None

`python
from openpyxl import load_workbook

第一种方式:读计算结果(但有坑)

wb = load_workbook('报表.xlsx', data_only=True)
ws = wb.active
print(ws['A10'].value) # 可能输出None,尤其是公式引用外部文件时

解决方案:先让Excel保存为值,再用pandas读取

或者用xlwings实时计算(需要Excel进程)

import xlwings as xw
app = xw.App(visible=False) # 后台运行,不弹窗口
wb = app.books.open('报表.xlsx')
ws = wb.sheets['Sheet1']
value = ws.range('A10').value # 这个是实时计算的
wb.close()
app.quit()
`

个人吐槽:Excel公式在自动化里就是颗定时炸弹。我现在的原则是:如果数据源有公式,先让同事“复制-粘贴为值”,不然就自己用Python重新计算。

核心示意图:一张流程图展示数据从原始Excel → pandas清洗 → 新Excel输出的完整链路,标注关键步骤的处理时间。

实战2:给1000个单元格改格式,UI操作 vs 代码

上个月要生成200份客户对账单,每份需要把“欠款金额”超过10万的单元格标红加粗。手动改?干到凌晨2点。

`python
from openpyxl import load_workbook
from openpyxl.styles import Font, PatternFill

为什么要用openpyxl而不是pandas:pandas对格式控制几乎等于0

wb = load_workbook('对账单模板.xlsx')
ws = wb.active

定义样式:红色背景+加粗白色字体

red_fill = PatternFill(start_color='FF0000', end_color='FF0000', fill_type='solid')
red_font = Font(bold=True, color='FFFFFF')

遍历B列(从第2行开始,第1行是标题)

for row in range(2, ws.max_row + 1):
cell = ws.cell(row=row, column=2) # column=2就是B列
if isinstance(cell.value, (int, float)) and cell.value > 100000:
cell.fill = red_fill
cell.font = red_font

保存并覆盖原文件

wb.save('对账单_已处理.xlsx')
`

性能数据:1000个单元格的样式修改,0.2秒搞定。同一个操作在Excel里手动做?保守估计15分钟。

还有个技巧:用pandas处理“脏数据”

Excel里经常有“合并单元格”这种反人类设计。读进去的全是NaN,合并后只有第一行有值。用fillna(method=’ffill’)解决:

`python
import pandas as pd

df = pd.read_excel('脏数据.xlsx', header=None)

假设第1列有很多合并单元格,导致后面行是NaN

df[0] = df[0].fillna(method='ffill') # 向前填充,跟Excel的“向下填充”一个意思

删除全为NaN的行(有些合并单元格带来的空行)

df = df.dropna(how='all')

重新设置第一行为列名

df.columns = df.iloc[0]
df = df[1:].reset_index(drop=True)
`

官方文档骂娘时刻fillna的文档写的是“Fill NA/NaN values”,但没告诉你method=’ffill’在大型DataFrame上的性能比循环快100倍。我只想说:写文档的人可能没处理过10万行以上的数据。

总结前示意图:一张柱状图对比手动操作vs Python自动化的时间消耗,涵盖数据合并、格式修改、公式计算、报表生成四个场景。

总结一下,你可以立刻用的三个点

  • 读Excel优先pandas:用pd.read_excel(),指定engine=’openpyxl’,加sheet_name避免读错表。不要碰xlrd了,它已经退休了。
  • 处理公式用xlwings:openpyxl读公式容易翻车(data_only=True也不可靠),xlwings虽然需要Excel进程,但数据实时准确,适合做自动化报表。
  • 文件合并用concat:先把所有DataFrame放进列表,最后一次性pd.concat()`。不要边读边拼,内存会炸。我亲眼见过50万行数据在循环里append,内存飙到8GB。
  • 最后一句掏心窝的话:能用代码解决的,别用手。能自动化解决的,别熬夜。

    滚动至顶部