拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python自动化报表生成:从手工复制粘贴到一键搞定

Python自动化报表生成:从手工复制粘贴到一键搞定

先说个背景吧。我接到的任务本身不复杂,但特别磨人:每天上班第一件事,登进内部系统,按业务线逐张导报表,导完以后打开Excel手工复制粘贴,把七八个sheet合并成一张总表,再做去重、补空值、统一时间格式,最后手动生成几个统计数字,塞进周报里给领导发出去。一开始数据量小,忍忍也就过去了;等业务跑起来之后,一天光是对数、改格式就能耗掉快一个小时,还老担心哪一列拷错了、哪一行漏掉了。那段时间连续加班,有一回半夜导出报表后发现自己把两个相似sheet搞混了,站在项目室差点没笑出来。于是我很认真地坐下来,用两个晚上做了一个自动化脚本,把整套流程从“人肉流水线”改成了“Python一条命令搞定”。

这次做的东西,就是典型的Python自动化开发。底层逻辑并不神秘,无非是让脚本去替代那些重复度高、规则明确、需要按固定格式反复执行的操作。整个过程涉及环境安装、库的选择、代码设计、异常处理、后期优化,最后还把脚本打包成了能定时运行的独立任务。这篇就完整复盘一下,从需求梳理到最终落地,把当时选型和踩坑的细节都写出来,给以后做类似工作留个存档,也供有同样困惑的朋友抄作业。

1. 需求场景与项目目标

1.1 这个自动化任务到底在解决什么

很多刚接触自动化的人,第一反应是“这玩意儿是不是得上很高深的技术”,其实真不是。自动化开发的第一步永远是搞清楚你每天手动做的事到底是什么,规则能不能被程序描述。我的任务看起来是“拉表、合并、统计、写报告”,真正拆开后其实是四件事:

  • 定时登录内部系统,按固定条件取数据;
  • 把不同来源的数据合并到一个结构里;
  • 清洗脏数据:去空行、去重、统一字段类型和日期格式;
  • 按模板生成Excel报表,附上统计数字和趋势图。

这四件事全部是确定性规则,不涉及太多主观判断,天然适合用脚本跑。我当时最想省掉的不是拉数动作本身,而是“合并表时总担心出错”的心理成本——毕竟人手操作的错误率在小样本时看不出来,一旦数据量上了几百行,任何一列错位都会让整个周报失真。自动化最核心的价值不是快,是稳定可复现,同样的输入永远得到同样的输出,这对数据类工作来说比什么都重要。

1.2 为什么选Python而不是现成工具

可能有人问,现在的BI工具、报表系统不是都能自动拉数和生成图表吗?确实可以,但我这边的限制比较现实:内部系统只给了浏览页面,导出Excel都要靠手工点按钮;BI工具权限申请流程长,而且我要做的不是一张看板,是一份带很多手工调整痕迹的月度汇总表。换到Python这边,requests、pandas、openpyxl这些库一组合,就把“页面操作”直接跳过了,数据从接口拿,处理和输出全部本地完成,从入口到出口都是自己控制。

Python的另一个优势是生态成熟,网上现成代码多,几乎你会遇到的每个小问题都有人踩过。哪怕是我这种平时不常写技术代码的人,只要会定义函数、会用列表和字典、能看明白异常提示,就能把自动化工具搭起来。后来的实际情况也验证了这点:整个项目核心代码量不到六百行,真正的难点反倒是环境安装和依赖管理——这部分我会在下一节展开。

2. 环境搭建与基础配置

2.1 Python安装与版本选择

这次我选的Python版本是3.10。为什么不是最新的3.12或3.13?理由其实很现实:pandas、openpyxl、requests这些库在3.10上全部有稳定轮子,不用担心某个依赖还没适配新版本。另一个原因是公司的另一台Linux服务器上已经把3.10当成默认Python版本,本地开发和服务器部署保持一致,能少踩很多环境差异的坑。

安装路径上,Windows用户我建议直接去官网下安装包,注意勾选“Add Python to PATH”。这个勾选很重要,很多人装完以后在命令行敲python提示找不到命令,基本都是因为它没勾上。Linux环境则要小心系统自带的Python版本不可乱动,许多系统工具依赖它,所以我更推荐用pyenv或miniconda来管理独立环境,而不是直接替换系统默认python。当时我在一台Ubuntu服务器上跑定时任务,就直接用docker拉了个python:3.10-slim镜像,把脚本和依赖打包进去,既不会污染宿主机,也方便迁移。

还有一个容易踩的细节:装完以后命令行输入python --version看到的版本,和你实际运行脚本的版本可能不是同一个。尤其是Windows里如果装了多个Python,或者用过Anaconda,PATH的顺序会决定到底调用哪个。我建议在项目根目录用python -c "import sys; print(sys.executable)"确认当前解释器的绝对路径,这一步的成本极低,却能在后面省掉大量查“为什么库装了我却import不进来”的时间。

2.2 VSCode里的Python环境配置

编辑器我用的VSCode,配合Python和Pylance插件。很多新手容易忽略的关键点是:VSCode里右下角要手动选择解释器。如果你没选,VSCode大概率会用某个全局默认解释器,而你的依赖装在虚拟环境里,结果就是编辑器无脑报“导入requests失败”,可你在终端运行脚本又一切正常——这个问题我当时排查了好一会儿。

具体的配置流程很简单。先创建一个项目文件夹,在终端执行python -m venv .venv创建虚拟环境,然后Ctrl+Shift+P调出命令面板,输入“Python: Select Interpreter”,选到.venv\Scripts\python.exe。之后所有终端的激活命令也不要忘了:Windows是.venv\Scripts\activate,Linux和Mac是source .venv/bin/activate。激活成功后命令行前面会多一个.venv的标识,看到它你才知道当前确实用的是虚拟环境。

VSCode还有一个值得开的选项是文件保存时启用的格式化,建议在settings里把format on save设成true,配上默认的black或autopep8。自动化脚本经常要反复改,代码格式统一之后,看diff和改bug都舒服很多。我不是那种代码洁癖很严重的人,但这次靠着格式化省掉了很多低级缩进错误——Python的缩进就是语法的一部分,一个看不见的Tab混空格就能让整段代码罢工。

2.3 依赖库和虚拟环境管理

依赖管理我自己用的是最朴素的requirements.txt。把需要的库写进去,锁一下版本,别人拿到项目后只需要执行pip install -r requirements.txt就能把环境复现出来。这次我用的核心库如下:

库名用途安装时的注意点
requests请求内部系统接口,保持登录会话新版一般不用额外依赖,装完可直接用
pandas数据读入、合并、去重、字段处理依赖numpy,安装慢时建议用国内镜像源
numpypandas底层数值运算尽量和pandas版本匹配,避免二进制不兼容
openpyxl生成和美化Excel文件独立库,专门处理xlsx格式
matplotlib绘制趋势图画中文时注意字体设置
schedule实现定时调度轻量,适合单机任务

这里有个很常见的坑:直接用pip install pandas可能会因为墙外的源慢到怀疑人生,甚至超时失败。我当时的做法是加上阿里云镜像:pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/。装库失败的时候搞清楚是网络问题还是版本冲突,最容易判断的办法是单独装其中一个库看报错信息,而别在那一长串依赖里瞎猜。

还有一点,我始终没有把账号密码写进代码。把敏感信息放在环境变量或单独的config.ini文件里,然后让代码读取。这既是安全习惯,也是为了方便换环境迁移——万一脚本要部署到服务器,总不能因为密码变了就去改代码。

3. 脚本结构与处理流程设计

3.1 先把手工流程翻译成程序流程

真正动手写代码之前,我花了大概一小时画了一张“人工操作流程图”。所谓画图不是用那些专业工具,就是拿纸笔一步步写:打开系统→登录→点查询→导出Excel→打开汇总表→全选复制→粘贴→删重复→改日期格式……写完以后再把每一个手工动作换成对应的代码动作。这一步看似笨,但特别管用,它能让你一上来就看到哪些步骤可以合并、哪些步骤可以省略、哪些步骤其实是重复劳动。

比如我原来手动操作时要先把数据从Excel里复制出来,再插到总表里。而代码里根本不需要这个中间落地,直接从接口拿到JSON数据,解析成DataFrame,再合并到总表DataFrame,最后一次性写Excel。少了一个中间文件,就少了很多“文件没保存”“格式错乱”之类的意外。程序流程的逻辑线是:

数据获取(requests请求)→ 数据解析(JSON转DataFrame)→ 数据清洗(去空、类型转换、去重)→ 数据聚合(groupby统计)→ 报表生成(openpyxl写Excel+matplotlib画图)→ 本地保存与日志输出。

这条流水线设计成单向的,每一段的输入输出都很明确。好处是任何一个环节出了问题,都能很快定位到出错的函数,不用在一个大脚本里上下翻找。

3.2 模块划分与函数定义

我见过很多初学自动化的人喜欢把几百行代码写在一个文件里,短时间能跑通,但稍微改点需求就得小心翼翼,一不小心就把别处弄崩了。这次我一开始就按功能模块拆了文件,目录结构大概是:

auto_report/ ├── config.ini # 连接参数、账号信息、路径配置 ├── requirements.txt ├── main.py # 程序入口,调度各模块 ├── api_client.py # 登录、拉取数据的封装 ├── data_clean.py # 清洗、去重、类型转换 ├── report_writer.py # 生成Excel和图表的封装 └── logger.py # 日志记录

main.py的代码很短,核心逻辑就是读取配置,依次调用各模块。下面是我当时的大致写法:

import configparser from api_client import ApiClient from data_clean import clean_data from report_writer import write_report from logger import setup_logger def main(): logger = setup_logger() cfg = configparser.ConfigParser() cfg.read('config.ini', encoding='utf-8') client = ApiClient(cfg['server']) raw_data = client.fetch_reports(cfg['query']) df = clean_data(raw_data) logger.info(f'清洗完成,剩余 {len(df)} 行数据') write_report(df, cfg['output']) logger.info('报表生成完毕') if __name__ == '__main__': main()

这样的好处非常直接:看main.py就能知道整个程序做了什么,想改哪块就进哪个文件。定义函数这件事在自动化开发里不是什么高深技巧,但它是保证代码可维护性的底线。每个函数只做一件事,名字起得直白一点,比如fetch_reports就是拉数据,clean_data就是清洗数据,哪怕过两周回头再看,也能一眼get到思路。

3.3 数据清洗:类型转换与数组切片

清洗阶段是我自定义的流程中花费时间最长的一环。业务数据从接口下来后,往往存在各种“脏”情况:空值、字符串里的多余空格、日期字段有的是字符串有的是datetime对象、数字列里混着“未统计”这样的文本。这时候pandas提供了很多特别省事的方法,但如果你是刚接触,一定要养成先看字段类型的习惯。

DataFrame.dtypes能告诉你每一列的类型。然后你可能会发现,数字列被读成了object,时间列被读成了字符串。处理方式我用得比较密集的有两个:

import pandas as pd df['amount'] = pd.to_numeric(df['amount'], errors='coerce') df['report_date'] = pd.to_datetime(df['report_date'], format='%Y-%m-%d', errors='coerce')

to_numeric后面的errors='coerce'表示转换不了的置成缺失值,避免因为一个异常字符导致整个转换失败。to_datetime里的format参数非常推荐显式指定,不指定虽然也能猜,但猜错的概率不低,一旦日期格式有天差地别,后面排序和分组就全乱了。

再说数组切片。Python的列表、NumPy数组和DataFrame都支持切片,我这次用得频繁的是df.iloc[:, 2:5]这种按位置取列,以及df.loc[df['status'] == '已完成']这种按条件取行。切片看着简单,但有一个新手特别容易犯的错:直接用df = df[df['amount'] > 0]能正常过滤,可如果只是取一部分列赋值给新变量,没有用.copy(),后续修改新变量时可能连同原DataFrame一起改掉。我当时就踩过这个坑,统计完准备写报告,发现原数据被意外改了,排查下来是视图和副本的引用问题。所以只要你想对切片后的结果做修改,最好养成加.copy()的习惯。

4. 核心功能实现与代码

4.1 登录内部系统并自动拉取数据

项目里最关键也最容易被低估的一步,是“让代码像人一样登录系统并拿到数据”。如果系统有正规开放的API,那最好,直接用requests.post把用户名密码发过去换一个token就行。但我这边系统的接口文档不公开,只能自己分析网页的登录请求,用浏览器开发者工具查看提交的参数和Cookie策略。

我封装的ApiClient大概是这个样子:

import requests import time class ApiClient: def __init__(self, server_cfg): self.base_url = server_cfg['base_url'] self.session = requests.Session() self.session.headers.update({'User-Agent': 'Mozilla/5.0'}) def login(self, username, password): login_url = f'{self.base_url}/api/login' resp = self.session.post(login_url, json={ 'username': username, 'password': password }, timeout=10) resp.raise_for_status() return resp.json() def fetch_reports(self, query): url = f'{self.base_url}/api/reports' params = {'date_from': query['start'], 'date_to': query['end']} for attempt in range(3): try: resp = self.session.get(url, params=params, timeout=30) resp.raise_for_status() return resp.json() except requests.RequestException as e: print(f'第 {attempt + 1} 次请求失败: {e}') time.sleep(2 * (attempt + 1)) raise RuntimeError('连续三次请求失败,请检查服务状态')

用requests.Session而不是每次都新建请求,最大的好处是它能自动维持登录后的Cookie。我加了一个简单的重试机制,处理网络抖动或系统偶发超时。这里有两个细节值得说:一,timeout参数一定要设置,否则请求挂死会让整个定时任务卡住;二,异常时不要马上重试,用指数退避,也就是第一次等2秒、第二次等4秒。这种小技巧在很多现成教程里不会讲,但生产环境里特别实用。

如果你要自动化拉取的是不开放接口的系统,绕不开登录鉴权时,可以在代码里加入明文密码的警示:不要写死在源码里,优先读环境变量,或者用系统级的凭据管理工具。我在config.ini里只是留了一个占位符,真正常用的是os.environ.get('AUTO_REPORT_PWD')。安全习惯这种东西一开始嫌麻烦,后期遇到问题就后悔没早养成。

4.2 数据清洗与去重逻辑

拿到原始数据后,我习惯先看一眼形状和字段列表:df.shape、df.columns。数据量大时不要直接打印全部内容,用df.head()看前几行就够了,否则控制台刷屏不说,还容易卡死编辑器。

去重逻辑上,不是简单调用df.drop_duplicates()就完事。我这次的需求是“同一个订单号只保留最新状态的一条记录”,那就要先按订单号分组,再按时间排序取最后一条。代码是:

df = df.sort_values('update_time') df = df.drop_duplicates(subset=['order_no'], keep='last')

keep='last'配合排序后的顺序,能准确实现“保留最新状态”。如果直接用默认去重,保留的是第一次出现的记录,很可能不是你要的版本。这个细节特别值得注意,业务上的“去重”极少是无脑删重,多半带着“保留哪一条”的隐含规则。

清洗阶段我还会删掉全空的行和列:

df = df.dropna(how='all') df = df.dropna(axis=1, how='all')

dropna同样有很多参数,how='all'表示整行或整列全是空值才删除。千万别一不小心写成dropna()默认形式,那会把任何带空值的行全删了,数据量瞬间少一大块,你还没察觉。

4.3 生成Excel报表和趋势图

写Excel这一步,我用的是openpyxl,因为它能直接控制单元格样式,比如列宽、字体、颜色、冻结窗格、自动筛选,生成出来的报表和人手做的观感差距不大。pandas本身有to_excel方法,但它更适合快速导出数据,样式控制相对弱一些。

我的做法是用pandas先计算好所有要展示的数据,再用openpyxl逐项写入并美化。核心代码大概是:

from openpyxl import Workbook from openpyxl.styles import Font, PatternFill from openpyxl.utils.dataframe import dataframe_to_rows def write_report(df, output_path): wb = Workbook() ws = wb.active ws.title = '汇总' header_font = Font(bold=True, color='FFFFFF') header_fill = PatternFill(start_color='4F81BD', end_color='4F81BD', fill_type='solid') for c_idx, col in enumerate(df.columns, start=1): cell = ws.cell(row=1, column=c_idx, value=str(col)) cell.font = header_font cell.fill = header_fill for r_idx, row in enumerate(df.itertuples(index=False), start=2): for c_idx, value in enumerate(row, start=1): ws.cell(row=r_idx, column=c_idx, value=value) ws.column_dimensions['A'].width = 20 ws.freeze_panes = 'A2' ws.auto_filter.ref = ws.dimensions wb.save(output_path)

这里用dataframe_to_rows会省很多事,但需要注意中文列名和数值类型,别让Excel把长数字变成科学计数法。那次自动化报表里有一列是订单编号,纯数字有十几位,直接写入会显示成1.23E+12。解决办法是写入前先把该列转成字符串,或者设置单元格格式为文本。我用的方案是统一转字符串:

df['order_no'] = df['order_no'].astype(str)

趋势图方面,matplotlib常规操作是先画图再插入Excel。有个小坑必须提醒:日期横坐标如果太密集,标签会全挤成一团,根本看不清。我当时一周一张图还好,后来同事让我生成按天三十天的趋势,直接把X轴标签挤成了黑坨。解决方法是主动设置间距:

import matplotlib.pyplot as plt import matplotlib.dates as mdates fig, ax = plt.subplots(figsize=(10, 4)) ax.plot(df['report_date'], df['amount']) ax.xaxis.set_major_locator(mdates.DayLocator(interval=5)) ax.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d')) plt.xticks(rotation=45) plt.tight_layout() plt.savefig('trend.png', dpi=150)

DayLocator(interval=5)的意思是每隔5天显示一个刻度,旋转45度是防止最后的标签重叠。再加一个tight_layout,图表四周留白就不会被裁掉。这个坑后来同事也遇到过,所以我把它单独拎出来,算是自动化报表里高频出现的“小毛病”。

4.4 补充:自动化脚本的拓展封装

做完第一版能用的脚本后,我发现它只能“手动在命令行里运行”,还不够自动化。于是我加了两层能力。

第一层是用Python标准库subprocess调用系统命令来完成一些周边操作。比如生成报表后,需要把最新文件拷贝到共享目录,或者压缩成zip归档。人工做这些很烦,但我可以让脚本自己调用命令:

import subprocess result = subprocess.run( ['zip', '-r', 'report_archive.zip', 'output/'], capture_output=True, text=True ) if result.returncode != 0: print(result.stderr)

这个模块的本质就是让Python替你在新进程里执行原本要手敲的命令,非常契合自动化的场景。但有一点要注意:能用Python库完成的事尽量别绕道去调系统命令,比如压缩文件,我更推荐直接用zipfile库,因为这样代码在不同操作系统上表现更一致。subprocess更多是用来调那些没有Python替代方案的专用工具。

第二层是定时调度。我的脚本最终部署在服务器上,用Linux的crontab跑最简单:

30 9 * * * cd /opt/auto_report && /opt/auto_report/.venv/bin/python main.py >> report.log 2>&1

这行的含义是每天9点30分执行脚本,并把输出写入日志。如果你在Windows环境,可以用“任务计划程序”或直接加一个轻量的schedule库到代码里:

import schedule import time schedule.every().day.at('09:30').do(main) while True: schedule.run_pending() time.sleep(60)

定时任务有个天然坑:脚本运行过程中一旦卡住,后续任务就会堆叠阻塞。所以我在脚本里加了超时控制,在拉数循环里做最大次数限制,还会把执行结果写进日志文件。日志是排查一切问题的基础,千万别嫌麻烦省掉,否则线上出bug你连从哪下手都不知道。

5. 调试与优化实录

5.1 处理“整型、字符串来回打架”的报错

开发过程中我遇到最多的异常就是类型不匹配。最典型的一次,程序报ufunc 'multiply' cannot use operands with types dtype('<M8[ns]') and dtype('float64')。当时我立刻懵了,盯着报错看了半天,最后发现问题出在:我把一个含日期列的DataFrame和一个含金额的Series直接相乘,逻辑上完全不对,纯粹是自己写错了需求。

这个经历给我的教训是:面对报错,第一件事不是去搜错误信息,而是回看自己要对数据做什么操作。类型转换不是靠猜的,而是要清楚知道每一列应该是什么类型。用pd.to_datetime转换日期,用pd.to_numeric转换数值,用astype(str)转换ID字符。关键是要在你需要做计算之前就完成转换,而不是等到运算报错才回头补。

另一个经验是尽量用errors='coerce'。它的好处前面说过,转换不了的部分变成缺失值,而不会让整个操作崩掉。但注意,这会导致一部分数据静静地变成空值,所以转换完必须检查一下空值比例。如果空值比例异常高,说明原始数据格式和你预想的不一致,需要回头核对接口返回字段。

5.2 依赖冲突和爬取环节超时

中间有一个版本问题是让我印象很深的:我一开始随手装了最新版的pandas,结果它同时把一个新版的numpy也带上来了。另一个旧项目里固定使用numpy旧接口,两个项目共享同一个Python环境后,旧项目直接跑不起来了。这个问题的根源就是没有隔离环境。

解决办法也很简单:不同项目建不同虚拟环境,依赖版本全部锁在requirements.txt里。如果服务器上已经一团乱,最省事的方案是用Docker重新跑一个干净容器,我当时在Ubuntu上就是这么干的:写一个Dockerfile,里面FROM python:3.10-slim,COPY requirements.txt,然后RUN pip install,这样宿主机Python再怎么乱都不影响自动化任务。

超时问题更常见。我写定时任务后,有一天下载数据比平时慢了一倍,所有环节都在等requests返回。我之前加的3次重试机制能兜底,但如果每次都等到30秒超时才重试,效率太低。更合理的做法是把超时时间设成一个配置项,在系统慢的时段适当调大,同时把请求改为流式处理,避免一次性把所有数据都载入内存。对于数据量特别大的接口,分页拉取是标准解法:每次只拿几百条,翻页循环,最后合并。虽然代码多一点,但内存占用和单次请求成功率都明显改善。

5.3 性能优化:减少无效计算和频繁调用

脚本上线后跑了几周,运行时间越来越长。我一度怀疑是不是服务器负载问题,后来用cProfile跑了一次性能分析,才发现有一半时间花在反复调用一个用途不大的OCR接口上。事情是这样的:最初为了兼容某些扫描件数据,我引入了一个OCR识别库,用它识别截图里的文字。但实际业务里,绝大多数数据都来自结构化接口,OCR是纯兜底场景,而且那个库在CPU上跑起来资源占用很夸张,一张图就要吃掉不少计算资源,批量环境下直接就卡住了。

我最后做的优化策略是“优先走结构化接口,OCR只在完全拿不到数据时才启用”,并且把OCR调用放成独立子进程,设置超时后自动杀掉。这个改动让整体耗时从三分钟降到了四十秒。自动化开发里一个非常重要的原则是:能用接口拿到的数据绝不靠解析页面,能解析页面就绝不靠OCR,层级越靠前的方案越稳定、越快。很多工具看着炫,但未必适合你的高频主流程。

优化还体现在代码细节:循环里不要反复调用df.loc去查数据,能用向量化操作就用向量化;写Excel时不要一行一行cell.value =去设置,尽量整列赋值;日志里也不要输出太庞大的DataFrame内容,否则全是IO开销。这一块只要做到“数据往内存里少倒腾几趟”,效率就能提升一个量级。

6. 常见问题排查速查与避坑技巧

6.1 问题排查速查表

我把这次开发和上线过程中遇到过的典型问题整理成了表格,方便以后快速对照。

现象可能原因解决思路
pip安装库失败网络慢或镜像源不稳定换用阿里云、清华等镜像源,或设置代理(合规网络环境下配置)
命令行敲python没反应未添加PATH或解释器冲突安装时勾选Add to PATH,用sys.executable确认解释器路径
编辑器报错但命令行运行正常VSCode选错解释器选择虚拟环境对应的Python解释器
df过滤后修改影响原数据未使用.copy()导致视图引用切片结果要修改时主动加.copy()
日期列转成时间后全是NaT原始日期格式不匹配显式指定format参数,常见格式要事先整理好
大数字变成科学计数法Excel默认格式问题写入前转为字符串或改单元格数字格式
定时任务卡死请求未设timeout为所有网络请求设置超时上限和重试次数
脚本运行占用内存过大一次性加载全量数据分页拉取,处理完的数据及时释放引用

这个表格是我踩坑之后的真实汇总,省得下次再重复翻文档。其实大多数自动化脚本的问题,最后都能归到“环境不一致”和“数据格式不好”这两大类上,提前在入口处做好检验,比事后到处打补丁强一百倍。

6.2 独家实操技巧

有几个技巧不是教程里能学到的,但实战中特别好用,我单独说一下。

第一,日志要分文件写。不要把print当作日志用。我当时用Python自带的logging模块,把INFO和ERROR分开输出到不同文件,这样任务失败时只要看error.log就知道问题所在,不用在几十MB的stdout里翻关键信息。日志格式里务必带上时间戳和函数名,定位问题的速度完全不一样。

第二,写Excel之前先备份。脚本一旦跑起来,覆盖文件是秒级的事。我经历过一次因为在测试环境跑了一遍完整脚本,直接把生产汇总表覆盖了,还好那个表是从历史数据重建的,不然真会出事故。后来我在代码里加了自动备份逻辑:凡是输出路径已存在,就先重命名成带时间戳的备份文件,再写新文件。

第三,开发阶段一定要先用一小份样本数据跑通全流程,再上全量数据。我第一版代码去重逻辑写反了,如果不是先用20行样本数据测试,直接跑全量数据那天的报表全都会错。小样本验证的时间成本极低,却能避免最贵的错误。

第四,代码里写好注释,命名别偷懒。建议函数名和变量名都用完整的英文单词组合,比如pending_orders、archived_files,千万别用a、b、tmp这种。自动化脚本可能几个月后还要改,到那时候你唯一能依赖的就是清晰的命名和注释。

结尾:一点个人体会

这次Python自动化开发做下来,我最深的感受是:自动化真正的难度不在写代码,而在“把你的工作语言翻译成程序语言”。翻译得越准确,脚本就越可靠,维护成本就越低。我后来把它扩展成了一个小工具集,每天定时跑,偶尔有异常也最多是重试几次就解决,我再也没有为合并报表加班过。回想起来,最值得的投入不是那两晚上的编码,而是前面花掉的梳理流程和确认需求的时间。如果你也想复制这种“一劳永逸”的效果,不妨就从你手头最烦的那件重复事开始,像我一样把流程先写下来,再一句一句让它变成Python代码。

返回列表