ARTICLE · 1126233
用 Python 自动处理 Excel:告别人工复制粘贴
每个月底,你都要经历一次这种折磨
每个月 1 号早上,12 个 Excel 文件准时躺在你的邮箱里:销售_01月.xlsx、销售_02月.xlsx……一直到销售_12月.xlsx。每个文件结构一模一样,都是订单明细。你的工作是把它们合并成一张总表,按产品和地区汇总,再拆出华东区的明细给区域经理。
手工做这件事的流程你是知道的:打开第一个文件,复制,粘贴到总表;打开第二个,复制,滚动到底部,粘贴……十二个文件下来,一个多小时没了,还不能保证没粘错行。上个月你就把 3 月的数据粘进了 2 月的区域,被老板叫去聊了十分钟。
今天这篇,我们把这个流程写成一个 Python 脚本。以后每月 1 号,你只需要双击运行,10 秒钟后喝着咖啡等结果。而且脚本月月能跑,一次编写,永久受益。
先造 12 个假文件
为了让代码可以直接运行,我们先用 Python 造 12 个月度销售文件,存到一个文件夹里。真实场景中,这一步就是"把 12 个文件放进同一个文件夹":
import pandas as pdimport numpy as npimport osnp.random.seed(42)os.makedirs('月度数据', exist_ok=True) # 建一个文件夹放 Excelproducts = ['笔记本电脑', '无线鼠标', '机械键盘', '显示器', '扩展坞']regions = ['华东', '华北', '华南']for month in range(1, 13):n = np.random.randint(40, 80) # 每月订单数量不等,模拟真实情况d = pd.DataFrame({'订单号': [f'{month:02d}{i:04d}' for i in range(n)],'产品': np.random.choice(products, n),'地区': np.random.choice(regions, n),'数量': np.random.randint(1, 10, n),'单价': np.random.choice([5499, 129, 399, 1299, 259], n),'销售员': np.random.choice(['张伟', '李娜', '王强', '刘芳'], n)})d['金额'] = d['数量'] * d['单价']d.to_excel(f'月度数据/销售_{month:02d}月.xlsx', index=False)print('12 个文件已生成')
批量读取:glob 找文件,循环读进来
核心是三个工具的配合:glob 负责把文件夹里所有符合条件的文件找出来,read_excel 负责读,concat 负责拼:
import globimport os# 找到文件夹里所有以"销售_"开头的 Excel 文件files = glob.glob('月度数据/销售_*.xlsx')print(f'找到 {len(files)} 个文件')frames = []for f in files:month = os.path.basename(f)[3:5] # 从文件名"销售_01月.xlsx"里切出"01"d = pd.read_excel(f)d['月份'] = int(month) # 加一列标记数据来自哪个月frames.append(d)all_data = pd.concat(frames, ignore_index=True)print(all_data.shape) # 大约 (690, 8):近 700 行明细合并完毕
有两处细节值得留意。一是星号 * 是通配符,销售_*.xlsx 表示"销售_开头、任意内容结尾的 Excel 文件",以后新增月份不用改代码。二是我们顺手从文件名里提取了月份存进新的一列,不然合并完就分不清每行数据是哪个月的了。
汇总:老本行 groupby
合并完得到 all_data,接下来就是前几篇练熟的 groupby 和透视表:
# 按产品汇总总销量和总金额summary = all_data.groupby('产品').agg(总数量=('数量', 'sum'),总金额=('金额', 'sum')).sort_values('总金额', ascending=False)# 按月看销售趋势monthly = all_data.groupby('月份')['金额'].sum()# 地区 × 月份 的透视表region = all_data.pivot_table(index='地区', columns='月份', values='金额', aggfunc='sum')print(summary)
拆分:一行条件筛选
老板要华东区的明细?一行条件筛选的事:
east = all_data[all_data['地区'] == '华东']print(f'华东区共 {len(east)} 条订单')
要拆三个地区,循环一下就行,后面我们会把它们写进同一个文件的不同 sheet。
写回 Excel:一个文件,多个 sheet
最后一步,把汇总结果写回一个漂亮的 Excel,不同内容放不同 sheet。这需要 ExcelWriter:
with pd.ExcelWriter('年度汇总报告.xlsx', engine='openpyxl') as writer:summary.to_excel(writer, sheet_name='产品汇总')monthly.to_excel(writer, sheet_name='月度趋势')region.to_excel(writer, sheet_name='地区透视')east.to_excel(writer, sheet_name='华东明细', index=False)
with 语句结束时会自动保存文件,不用担心忘记关闭。运行完打开"年度汇总报告.xlsx",你会看到 4 个 sheet:产品汇总、月度趋势、地区透视、华东明细,整整齐齐。
如果想给每个地区都出一个明细 sheet,把最后一行换成循环:
with pd.ExcelWriter('年度汇总报告_分地区.xlsx', engine='openpyxl') as writer:summary.to_excel(writer, sheet_name='产品汇总')for r in regions:sub = all_data[all_data['地区'] == r]sub.to_excel(writer, sheet_name=f'{r}明细', index=False)
如果运行时提示缺少 openpyxl,在终端执行 pip install openpyxl 装一下就好,它是 pandas 读写新版 Excel 文件依赖的引擎。
这套脚本的价值在哪里
我们算笔账:手工合并 12 个文件,算上手滑返工,大约 80 分钟;这个脚本跑完大约 10 秒。更重要的是它不会累、不会粘错行,下个月把新文件丢进文件夹再跑一遍就行。你省下的不只是时间,还有"反复核对有没有粘错"的心力。
这就是编程对职场人的真实意义:不是写多么高大上的程序,而是把重复劳动压缩成一次运行。
小结
这一篇我们完整走了一个办公自动化流程:glob 批量找文件,循环 read_excel 逐个读取并用文件名补充月份信息,concat 合并成总表,groupby 和 pivot_table 汇总,条件筛选拆分,最后用 ExcelWriter 把结果写进一个多 sheet 的 Excel 报告。
小练习:在本篇脚本的基础上加一个 sheet,内容是"每个销售员的月度销售金额"透视表(行是销售员,列是月份)。提示:和"地区透视"的做法几乎一样,只是换个 index。
下一篇预告
数据处理完了,图也画好了,可老板真正想要的其实是一句话:"所以,结论是什么?"下一篇我们聊点技术之外的东西。第 16 篇《数据分析报告怎么写:从数字到结论》,教你怎么把一堆表格和图表,变成一份让老板愿意看、看得懂、能拍板的报告。
本篇完整代码已经打包好,关注公众号,后台回复关键词【代码】即可领取。觉得有用就点个关注,我们下一篇见!