经常有朋友拿着一堆“能跑的脚本”找我救火:昨天还可以开的自动巡检,今天突然不执行了;测试脚本在本地好好的,一到服务器就各种点位不到;定时任务看起来成功退出了,实际上关键数据一条都没处理。这类问题碰多了以后,我慢慢意识到一个事实——自动化脚本开发,真正考验人的从来不是语法或多高深的算法,而是有没有一套稳定的“最佳实践”。这里的实践不是指某个框架的用法,而是从项目结构、配置管理、日志留痕、失败重试到可持续维护的整套习惯。
这篇文章想聊的,就是我在这些年里不断踩坑、复盘后沉淀下来的自动化脚本开发方法论,主要面向刚入门想系统学习脚本开发的同学,以及正在维护大量脚本却经常被稳定性折磨的后端、测试或运维方向的朋友。内容会比较长,但基本覆盖了脚本从设计、编码到稳定运行的每个关键环节,包括Web端和App端的UI自动化常见难点。如果你愿意按这些习惯改造手上的脚本,大概率能让脚本从“今天能用”变成“长期都能用”。
1. 先给脚本分好类,再谈实践
1.1 自动化脚本的常见类型与核心难点
提到自动化脚本,很多人第一时间想到的是“Python写点小工具”,但落到实际开发中,脚本的形态差异非常大。不把这些差异搞清楚,上来套一套很火的最佳实践,往往会出现南辕北辙的效果。
从我接触过的场景看,日常开发里的自动化脚本大致能分成五类:
- 数据处理类:批量导入导出、报表统计、数据清洗、文本解析。核心难点是数据格式多变,脏数据多,很容易跑一半就崩。
- 接口调用类:定时拉取第三方接口、推送消息、同步状态。核心难点是网络不稳定、接口字段会变、鉴权复杂,需要很强的容错与重试策略。
- UI自动化类:针对Web端或App端模拟用户操作,常见于自动化测试、RPA流程。核心难点是页面DOM变化快、等待时机难把握、环境差异影响大。
- 运维操作类:服务器巡检、日志清理、批量部署、健康检查。核心难点是高危命令多,脚本必须在“无人值守”场景下足够安全和幂等。
- 校验验证类:比如自动化测试脚本、数据一致性校验,主要用于上线前检查或每日巡检。核心难点是既要能覆盖业务规则,又不能写出脆弱的断言。
这五类脚本看起来都叫“自动化脚本”,但它们的可靠性模型完全不同。写数据处理脚本,你可以容忍运行时间长一点,但必须对异常数据有明显提示;写UI自动化脚本,一旦元素找不到,光是定位和等待策略就能占掉一半开发时间。因此,最佳实践的第一步,不是急着选框架,而是先确认自己写的到底是哪一类脚本,然后把设计重心放在这一类最脆弱的环节上。
1.2 为什么大多数自动化脚本活不过三个月
我见过很多项目的脚本,上线第一周表现很亮眼,但三个月后基本成为“僵尸脚本”,要么没人跑,要么跑了没人敢信。最典型的原因有几个。
第一,没有把脚本当成长期资产来维护。很多人写脚本时的心态是“帮我把这个事自动跑一遍”,于是配置写死在代码里、日志只往控制台打、出错了也不通知人,数据输出散落在一堆变量中。一旦业务需求调整,任何人也看不明白这段脚本当初的意图,只能推翻重写。
第二,忽视运行环境的一致性。脚本在开发机上用着当前环境跑通了,换一台电脑或部署到服务器就缺包、缺路径、缺环境变量。这类问题最容易消磨维护者对脚本的信任。
第三,错误处理太粗糙。最常见的是把所有异常用一种方式“包起来”,像“try ... except Exception: pass”这种写法,看起来脚本永远在成功,实际上所有的失败都被吞掉了。等某一天数据规则变化,脚本连续失败一周却没有任何人察觉,才是最危险的。
说到底,最佳实践要解决的其实不是“怎么把代码写漂亮”这种表面问题,而是如何让脚本具备长期可运行、失败可发现、问题可排查这三项核心能力。下面的内容,我会围绕这三件事展开。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 写脚本前先定骨架:目录结构与技术选型
2.1 一套能撑住长期演进的目录结构
脚本项目最忌讳的是“一个大文件走天下”。早期图省事,把所有的请求、解析、通知、异常处理都堆在同一个main.py里,一旦超过几百行就基本失去可维护性。我现在写脚本,除非是二三十行的一次性小工具,否则都会按下面的骨架来组织:
text复制my_automation/
├── config/
│ ├── settings.yaml
│ └── logging.yaml
├── core/
│ ├── http_client.py
│ ├── retry.py
│ └── logger.py
├── tasks/
│ ├── order_check.py
│ ├── data_sync.py
│ └── report_task.py
├── common/
│ ├── path_utils.py
│ ├── date_utils.py
│ └── file_utils.py
├── data/
│ ├── input/
│ └── output/
├── logs/
├── tests/
├── requirements.txt
└── main.py
这套结构我用了很长时间,每次参加评审都推荐团队使用。核心思路是把不同职责拆到不同目录,让“入口”“配置”“任务实现”“基础工具”互不干扰。
config目录放所有可变参数,业务人员或者未来的维护者不需要打开代码就能调整脚本行为。core目录放复用度高的基础能力,比如统一封装的http客户端、重试装饰器、日志初始化。tasks目录放每一类具体业务,比如“订单对账”“数据同步”,它们只关心自己的业务流,不关心底层实现细节。common目录放一些纯粹的工具函数。data目录管理输入输出文件,避免脚本运行时在任意路径生成临时产物。logs目录统一收日志,方便出错时集中排查。
也许有人觉得一个日用脚本搞这么多目录很重。我的观点是:如果这个脚本预计只会运行两三次,可以直接写成一页脚本;但只要它要“定时跑”或“交给别人维护”,这层结构省下来的排查时间,很快就会远超搭建结构花掉的时间。实际项目里,我经常发现很多bug最后都是因为文件位置混乱、配置散落导致,早一点规划目录会少走很多弯路。
2.2 配置外置:把“做什么”和“怎么做”分离
目录结构之外,另一个重点习惯是配置外置。脚本代码永远只描述“怎么做”,而那些可能会变的参数,例如接口地址、开关、发送目标、时间周期、数据库连接串,全部放到配置文件中。
拿一个很常见的巡检脚本举例,配置文件可以长这样:
yaml复制app:
name: order-check
timezone: Asia/Shanghai
data:
source_db_conn: "mysql+pymysql://readonly_user:xxxx@prod-mysql.internal/order_db"
order_api_base: "https://api.example.com/v1/orders"
date_offset_days: 1
check:
retry_times: 3
connect_timeout: 5
read_timeout: 30
target_file_
