告别手工统计一个 pandas 脚本如何帮我每周省下 2 小时说实话我最烦的事之一就是每周一早上打开 Excel把上周的业务数据复制粘贴、筛选排序、透视汇总最后做成一张「周报」发给老板。这套流程我重复了整整半年。每次至少 2 小时手酸眼累还特么经常出错。上周我把 Q2 的销售额多写了一个零被财务追着问了一下午。痛定思痛我决定用 Python pandas 写个自动化脚本把这破事彻底解决。问题手工报表到底耗在哪先说说我的工作场景。我们每周需要从三个数据源汇总数据业务数据库的订单表、CRM 系统的客户跟进记录、还有一个运维同事手工维护的 Excel。最后要生成三张表周度销售汇总、客户转化漏斗、以及各渠道流量对比。听起来不复杂对吧但实际操作起来数据库导出的 CSV 编码是 GBKExcel 打开直接乱码CRM 系统的导出格式每次都不一样列名还带空格运维的 Excel 里有合并单元格和批注pandas 读进来全是 NaN三张表之间要做 VLOOKUP数据量大了 Excel 直接卡死最气人的是这活儿每周都要来一遍。一样的步骤一样的坑一样的崩溃。方案一个脚本搞定全流程我的思路很简单把每周重复的操作全部脚本化输入三个原始文件输出三张汇总表。核心依赖就三个pandas、openpyxl、sqlalchemy。不用搞什么花里胡哨的框架实用第一。1. 统一数据读取层三个数据源格式各异我封装了一个load_data()函数自动处理编码、列名清洗、类型转换importpandasaspdimportnumpyasnpdefload_data(path,source_type):统一读取三种数据源ifsource_typecsv:# 自动检测编码dfpd.read_csv(path,encodingutf-8-sig)elifsource_typeexcel:dfpd.read_excel(path,engineopenpyxl)elifsource_typesql:fromsqlalchemyimportcreate_engine enginecreate_engine(mysqlpymysql://user:passhost/db)dfpd.read_sql(path,engine)# 列名清洗去空格、转小写、替换特殊字符df.columns(df.columns.str.strip().str.lower().str.replace(r[\s\-/],_,regexTrue))# 日期列统一转换date_colsdf.columns[df.columns.str.contains(date|time)]forcolindate_cols:df[col]pd.to_datetime(df[col],errorscoerce)returndf这段代码解决了我 80% 的读取问题。特别是encodingutf-8-sig这个参数专门对付 Windows 导出的 CSV 带 BOM 的坑。2. 数据清洗处理脏数据真实世界的数据永远比你想象的脏。我总结了几个高频问题合并单元格导致的空值# 前向填充把合并单元格的值补全df[category]df[category].fillna(methodffill)金额字段带人民币符号# 把「¥1,234.56」转成 1234.56df[amount](df[amount].astype(str).str.replace(r[¥,],,regexTrue).astype(float))重复记录去重# 按订单号去重保留最新记录dfdf.sort_values(update_time).drop_duplicates(order_id,keeplast)3. 三张报表的生成逻辑清洗完数据生成报表就是 pandas 的拿手好戏了。周度销售汇总defgen_sales_summary(df_orders):生成周度销售汇总summary(df_orders.groupby([category,sales_name]).agg({order_id:count,amount:sum,profit:sum}).rename(columns{order_id:订单数,amount:销售额,profit:毛利}))# 添加环比计算需要读取上周数据summary[环比_销售额]calc_week_over_week(summary[销售额])returnsummary客户转化漏斗defgen_funnel(df_crm):生成客户转化漏斗stages[线索,意向,报价,成交,复购]funnel(df_crm[stage].value_counts().reindex(stages,fill_value0))# 计算转化率funnel_dfpd.DataFrame({阶段:stages,人数:funnel.values,转化率:funnel.values/funnel.values[0]})returnfunnel_df渠道流量对比defgen_channel_compare(df_orders,df_traffic):生成渠道对比报表mergeddf_orders.merge(df_traffic,onchannel,howleft)channel_stats(merged.groupby(channel).agg({order_id:count,amount:sum,uv:sum}))# 计算客单价和转化率channel_stats[客单价]channel_stats[amount]/channel_stats[order_id]channel_stats[转化率]channel_stats[order_id]/channel_stats[uv]returnchannel_stats.sort_values(amount,ascendingFalse)4. 输出到 Excel格式美化pandas 默认导出的 Excel 太丑了我用 openpyxl 做了简单的格式美化fromopenpyxl.stylesimportFont,PatternFill,Alignmentfromopenpyxl.utils.dataframeimportdataframe_to_rowsdefexport_pretty_excel(dfs,filename):导出带格式的 Excel每个 DataFrame 一个 sheetwithpd.ExcelWriter(filename,engineopenpyxl)aswriter:forsheet_name,dfindfs.items():df.to_excel(writer,sheet_namesheet_name,indexFalse)# 获取 worksheetwswriter.sheets[sheet_name]# 表头样式蓝色背景 白色字体header_fillPatternFill(start_color4472C4,end_color4472C4,fill_typesolid)header_fontFont(colorFFFFFF,boldTrue)forcellinws[1]:cell.fillheader_fill cell.fontheader_font cell.alignmentAlignment(horizontalcenter)# 自动调整列宽forcolumninws.columns:max_lengthmax(len(str(cell.value))forcellincolumn)ws.column_dimensions[column[0].column_letter].widthmin(max_length2,30)踩坑记录真实世界里没有「干净」的数据脚本看起来简单实际写的时候踩了不少坑记录一下坑 1pandas 的 fillna(method‘ffill’) 被废弃了pandas 1.0 之后fillna(methodffill)会报 FutureWarning正确写法是ffill()df[category]df[category].ffill()# 新版本推荐坑 2merge 时数据类型不一致导致匹配失败两个表的order_id一个是 int一个是 strmerge 之后全是 NaN。解决办法是统一转成 strdf[order_id]df[order_id].astype(str)坑 3Excel 的日期格式被读成整数Excel 内部存储日期是从 1900-01-01 开始的天数pandas 读进来有时候是 float。必须显式转换df[date]pd.to_datetime(df[date],unitD,origin1899-12-30)坑 4中文路径导致编码错误Windows 上如果文件路径包含中文直接用pd.read_excel()可能报错。解决办法是用pathlibfrompathlibimportPath pathPath(rC:\\Users\\我的名字\\报表.xlsx)dfpd.read_excel(path)写在最后这个脚本我前后打磨了两周现在每周一早上我只要跑一条命令python weekly_report.py--week2026-W27然后泡杯咖啡等 30 秒三张报表就自动生成好了。比我原来手工做的好看而且不会出错。算下来每周省 2 小时一年就是 100 多个小时。相当于多出了两周的摸鱼时间哦不学习时间。如果你也在被重复的 Excel 操作折磨强烈推荐试试 pandas。刚开始可能会有点学习成本但一劳永逸的事值得投入。最后放个完整的脚本地址脱敏后的版本有需要的可以自取# 完整脚本已上传 GitHub Gist# https://gist.github.com/example/weekly-report-pandas有问题欢迎评论区交流。下周打算写如何用 Airflow 把这个脚本做成定时任务感兴趣的可以关注一下。