先说说为什么非要搞自动化。我接手的第一个项目是月度销售报表,3000多行数据,每天要更新,每行有十几个字段,还要做各种汇总。手动操作不仅慢,还容易出错。有一次把“销售额”列的数据类型搞错了,汇总结果差了好几十万,被领导训了一顿。从那以后,我就铁了心用Python。
第一步:选对工具
,0,.08);”
loading=”lazy” wi
dth=”800″ height=”500″>
别急着装xlrd、xlwt这些老古董,现在都2025年了,我推荐用openpyxl搭配pandas。为什么?
openpyxl:专门处理.xlsx格式,支持读写、公式、图表,功能全面pandas:数据处理神器,各种清洗、合并、分组操作一行搞定
安装很简单:
“bash
pip install openpyxl pandas
`
核心操作:读取与写入
先看一个最基本的例子。假设你有个Excel文件叫销售数据.xlsx,里面有三列:日期、产品名称、销售额。
`python
import pandas as pd
读取Excel文件,指定工作表名
df = pd.read_excel('销售数据.xlsx', sheet_name='Sheet1', engine='openpyxl')
看看数据长啥样
print(df.head())
简单统计:每个产品的总销售额
product_summary = df.groupby('产品名称')['销售额'].sum().reset_index()
print(product_summary)
`
这里为什么要用engine=’openpyxl’?因为pandas默认的引擎对.xlsx支持不太好,遇到复杂格式可能报错。我刚开始没加这个参数,结果一个带着合并单元格的文件直接崩了,心累。
还有个坑:pandas读取Excel时,如果列名有空格或特殊字符,会自动转成下划线。比如“产品名称”变成“产品名称_1”。所以最好在Excel里就把列名规范好,或者读取后用df.columns重命名。
数据清洗:那些反人类的设计
官方文档这段文档不够清晰,什么“inplace=True”“axis=1”,看得头皮发麻。我直接给你总结三个最实用场景。
场景1:处理空值
Excel里那些空白单元格,Python读进来就变成NaN。不处理的话,后续计算全崩。
`python
删除销售额为空的整行
df.dropna(subset=['销售额'], inplace=True)
用0填充所有NaN
df.fillna(0, inplace=True)
或者用均值填充
mean_sales = df['销售额'].mean()
df['销售额'].fillna(mean_sales, inplace=True)
`
我一般用第二种,因为产品销售数据里,空值通常意味着没卖出去,填0比较合理。
场景2:处理数据类型
这个设计真的反人类——Excel里看起来是数字的列,读进来可能变成字符串。比如“销售额”列里有个单元格不小心写成了“1,000”,Python就傻眼了。
`python
去掉逗号并转成数值
df['销售额'] = df['销售额'].astype(str).str.replace(',', '').astype(float)
日期列标准化
df['日期'] = pd.to_datetime(df['日期'], format='%Y-%m-%d')
`
场景3:去重
同一个订单号出现两次,算销售额时就要注意。
`python
按订单号去重,保留第一次出现的记录
df.drop_duplicates(subset=['订单号'], keep='first', inplace=True)
查看重复项
duplicates = df[df.duplicated(subset=['订单号'], keep=False)]
print(f"发现{len(duplicates)}条重复记录")
`
高级操作:报表自动化
另一个坑是生成报表。你以为写个分组汇总就完了?人家要的是带格式、带图表、带超链接的漂亮报表。
下面这段代码,能生成一个按月份和产品分组的销售汇总表,并加上条件格式:
`python
from openpyxl import Workbook
from openpyxl.styles import PatternFill, Font, Alignment
from openpyxl.utils.dataframe import dataframe_to_rows
准备数据:按月汇总
df['月份'] = df['日期'].dt.month
monthly_summary = df.groupby(['月份', '产品名称'])['销售额'].sum().reset_index()
创建Excel工作簿
wb = Workbook()
ws = wb.active
ws.title = "月度销售汇总"
写入数据
for r in dataframe_to_rows(monthly_summary, index=False, header=True):
ws.append(r)
设置格式
header_fill = PatternFill(start_color="FFC000", end_color="FFC000", fill_type="solid")
header_font = Font(bold=True, color="FFFFFF")
for cell in ws[1]:
cell.fill = header_fill
cell.font = header_font
cell.alignment = Alignment(horizontal='center')
自动调整列宽
for column in ws.columns:
max_length = 0
column_letter = column[0].column_letter
for cell in column:
if cell.value:
max_length = max(max_length, len(str(cell.value)))
ws.column_dimensions[column_letter].width = max_length + 2
保存
wb.save('月度销售汇总_自动化.xlsx')
print("报表生成完成!")
`
这个代码里踩过最大的坑是dataframe_to_rows这个函数。第一次用的时候忘了传index=False,结果多了一列索引号,怎么调都调不对,差点怀疑人生。
还有个技巧:如果需要追加数据到已有工作表,用openpyxl的load_workbook函数读取现有文件,然后操作ws.append。
实战案例:每天自动生成日报
我现在的流程是这样的:每天早上8点,脚本自动读取数据库导出的Excel,做清洗、汇总、生成带图表的新报表,然后发邮件给团队。整个过程不到3分钟。
核心代码片段:
`python
import schedule
import time
def daily_report():
# 1. 读取数据
df = pd.read_excel('今日销售数据.xlsx', engine='openpyxl')
# 2. 清洗
df.dropna(subset=['销售额'], inplace=True)
df['销售额'] = pd.to_numeric(df['销售额'], errors='coerce')
# 3. 汇总
summary = df.groupby('产品类别')['销售额'].sum().sort_values(ascending=False)
# 4. 生成报表(详细代码见上)
generate_report(summary)
# 5. 发送邮件(略)
print(f"日报生成完毕:{time.strftime('%Y-%m-%d %H:%M:%S')}")
每天8点执行
schedule.every().day.at("08:00").do(daily_report)
while True:
schedule.run_pending()
time.sleep(60)
`
这个设计真的反人类?不是,是很实用。但要注意:生产环境别用while True死循环,最好用cron或Windows任务计划。
总结一下,你可以立刻用的三个点
,别用老掉牙的xlrd记住:自动化不是为了炫技,是为了把重复劳动交给机器,让自己有时间去解决更复杂的问题。下次有人问你Python处理Excel,直接把这篇文章甩给他。