
每天早上一到工位先看的是昨夜的定时任务有没有挂。这不是危言耸听——在我用 Selenium 维护每日报表自动化的那段时间早上第一件事真的就是检查脚本日志、确认 Excel 有没有生成、邮件有没有发出去。一旦页面改版、登录验证策略升级或者浏览器驱动悄悄换了版本原本应该在八点半准时出现的报表就可能无声无息地消失。后来我把这套旧方案彻底换掉用了一套代号 1949 的轻量级自动化工具用可视化流程编排的方式重构了整条报表链路。这篇文章想说的就是这次重构的真实成本开发时间、维护开销、稳定性、团队交接以及那些不亲自跑一遍根本想不到的隐性支出。1. 先说背景一份每天都要跑的报表脚本为什么会让我烦到重构1.1 曾经用 Selenium 写日报任务的常规路径最开始那套方案其实没啥硬伤。当时我所在的小团队每天都要从内部数据后台拉前一天的运营报表然后整理成固定格式发给相关同事。这个操作本身特别机械打开网页、登录、选日期、点查询、等表格加载、翻页导出、把文件重命名、发邮件。一天一次工作日雷打不动。一开始靠人工点后来效率实在受不了就决定写脚本。我选了 Python Selenium ChromeDriver 这套组合理由是生态成熟、资料多、排查问题方便。脚本逻辑很简单核心代码长这样import time from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC options webdriver.ChromeOptions() options.add_argument(--headlessnew) driver webdriver.Chrome(optionsoptions) try: driver.get(https://report.example.internal/login) wait WebDriverWait(driver, 15) wait.until(EC.presence_of_element_located((By.ID, username))).send_keys(automation_user) driver.find_element(By.ID, password).send_keys(******) driver.find_element(By.ID, loginBtn).click() # 等待报表页加载 wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, table#reportTable tbody tr))) # 导出 Excel 按钮 driver.find_element(By.XPATH, //button[contains(text(),导出)]).click() time.sleep(2) finally: driver.quit()这段代码只是最简示意。真实的脚本远比它长有分页循环有日期参数拼接有下载目录的文件轮询有邮件发送有日志记录。但哪怕写得再完整它的本质仍然是“用代码描述浏览器的每一个行为”。代码能跑不代表它一直能跑。真正的维护成本是从“能跑”到“稳定跑”这个阶段才开始显现的。1.2 脚本逐渐失去信任的几个瞬间新旧方案真正拉开差距的不是第一天而是后面几个月的日常维护。我总结了一下旧方案崩溃的场景大概有这几类痛点具体表现平均恢复时间元素定位失效前端改版、动态 class 变化、按钮文案调整30-60 分钟驱动版本不匹配Chrome 自动升级后 ChromeDriver 报错20 分钟登录验证策略升级登录页加了验证码或双因素校验脚本直接卡死无法预估定时任务黑盒凌晨跑完就静默退出早上去看才发现数据是空的业务影响不可估量环境迁移麻烦换服务器、换 Python 版本依赖要重新装一遍半天起步无头模式难调试headless 下看不到页面状态只能靠猜每次追加日志再跑一轮最让我破防的一次是某天内部系统把查询按钮从“查询”改成了“查 询”中间插了一个空格。XPath 没匹配上脚本跑了一个小时全部失败而失败原因是因为一个文本里的空格。我不否认 Selenium 是成熟工具但它对页面变化的敏感度实在太高高到让人觉得“每次改版都是赌运”。除了脚本本身的脆弱还有一个更大的问题所有人对这个任务的人力投入是“定时关心”。数据库里没有跑成功的通知没有失败截图没有流程回放。脚本挂了之后它不会主动告诉你。等到业务同事来问“报表呢”你才知道要开始排查。2. 为什么选 1949 这套轻量级自动化选型逻辑和对比2.1 “可视化编程”到底在解决什么问题先说清楚可视化编程不是简单地把写代码变成拖积木。它解决的是一个非常实际的问题把“操作路径”变成“流程图节点”。你在界面上看到的每一步和你在真实浏览器里做的一步是对应的打开网址是一个节点填写表单是一个节点点击按钮是一个节点读取表格是一个节点发送消息是一个节点。用 Selenium 的时候我是在“编写一个自动化程序”。用可视化流程编排的时候我是在“描述一条操作流水线”。两者的目标一样但抽象层级完全不同。打个不恰当的比方Selenium 像自己搭建一辆车的发动机和管路每个零件都要自己调可视化流程编排像把现成的部件接成一条产线你不需要关心螺栓是怎么造的只要管好工序顺序和质检点。2.2 为什么不是重型 RPA也不是继续硬刚 Selenium在确定用代号 1949 这套工具之前我认真对比过三类方案继续优化 Selenium 脚本、上商业级重型 RPA、用轻量级自动化工具。方案学习门槛部署成本日常维护故障可观测性适合规模Selenium 脚本高需要 Python、XPath、CSS、浏览器原理中需要独立运行环境高页面改版就要改代码低默认静默失败单点任务、追求灵活性商业重型 RPA中但需要专门学习设计器和权限体系高通常要服务端、许可、审批流中流程健壮性较好高有审计日志跨系统集群级流程、合规审计1949 轻量级自动化低流程节点思维即可上手低客户端/单机部署低页面变化只需要重录节点高自带日志、截图、重试和通知中小团队日常重复操作继续优化 Selenium 可行吗可行。我可以加更多显式等待、更鲁棒的选择器、完善的日志模块、发送失败通知的钩子。但我意识到一个问题这个脚本只有我能维护。团队里其他人不会 Python也不会 XPath。一旦我请假或者调岗这套脚本就成黑盒了。上商业重型 RPA 又太夸张。我们是小团队单个报表任务每天跑一次投入一套需要专门服务端和多名管理员的基础设施属于明显的过度设计。而且商业 RPA 的授权费用和维护复杂度远超这个任务的收益。所以我把目光放在了中间地带要轻量、要单机可部署、要内建浏览器自动化能力、要自带日志和告警、要让不懂代码的同事也能看懂流程。1949 正好卡在这个位置。它的客户端装上就能用不需要额外的服务端流程就是一张节点图浏览器操作基于内置内核不用我自己维护 Chrome 驱动版本。2.3 选型时的妥协什么活交给脚本什么活交给流程选型不等于把原来的技能丢掉。我的实际做法是“混搭”1949 负责浏览器操作和流程调度数据清洗和一些复杂计算仍然交给已有的 Python 脚本只是通过命令行节点来调用。可视化流程不擅长的事情比如复杂正则、递归计算、深度循环这些内容放代码里确实更舒服。这个妥协很重要。如果你让可视化工具硬扛一切逻辑流程图会膨胀到没法看。如果你继续用脚本硬扛页面操作又要忍受元素定位的脆弱。正确姿势是让可视化工具承担它最擅长的高频页面交互让代码承担它最擅长的数据处理两者通过节点衔接。3. 重构实操从旧脚本拆解到 1949 流程落地3.1 第一步把旧脚本拆成一张操作地图重构之前我没有急着打开工具而是先把旧脚本从头到尾读一遍把它的执行链路画成一张操作清单。清单长这样登录打开登录页输入账号密码点击登录进入报表页点击菜单栏等待页面 loaded 状态设置查询参数把日期设为昨天选择渠道维度点击查询等待加载状态消失读取表格确认有数据行记录总行数分页导出循环点击下一页直到最后一页下载文件轮询下载目录确认 Excel 文件生成且大小不为 0发送邮件把文件通过企业邮箱发给相关同事记录日志输出本次任务的开始时间、结束时间、行数、文件路径这一步的作用不是画流程图而是逼迫自己搞清楚每一个输入、输出和异常分支。比如“表格没有数据”算成功还是失败“导出按钮点了但文件没出现”要怎么处理“登录失败”要不要立刻重试这些问题如果不在设计阶段想清楚到了搭建阶段一定手忙脚乱。3.2 第二步在 1949 里按节点搭流程打开 1949 客户端之后我新建了一个空白流程按操作清单依次添加节点。整体链路如下计划任务触发节点设置为每个工作日 08:20 执行打开网址节点填入内部系统的登录地址填写表单节点账号和密码来自配置项不写死在流程里点击登录节点等待元素出现节点等待首页某个导航菜单的可见状态超时 15 秒重试 3 次点击菜单节点进入报表查询页面填写日期节点这里我的技巧是直接输入文本“昨天”对应的日期而不是去点击日历控件省掉一堆日历定位问题点击查询节点等待条件节点等待“加载中”占位符消失而不是用固定 sleep提取表格数据节点读取表格行数并保存关键字段到数据集校验节点判断行数是否大于 0否则走异常分支导出节点点击导出按钮然后轮询下载目录等待新文件出现调用命令行节点运行那段 Python 数据清洗脚本把原始 Excel 转成最终报表格式发送消息节点把最终报表发送到工作群并附上执行摘要这里我比较推荐录制和手动拖节点结合。录制适合处理那些有动画、有滚动、有悬停下拉菜单的操作因为鼠标轨迹和时序会一并记录下来。手动拖节点适合控制流程逻辑比如分支判断、循环、等待条件。纯录制容易产生噪声操作纯手动搭建又太慢。3.3 第三步处理动态页面、定时调度和失败重试页面自动化最麻烦的就是动态加载。旧脚本里我大量用time.sleep(2)这种写法说实话很粗暴网络稍慢就超时网络快又白白等待。1949 里等待策略更明确等待元素可见、等待文本出现、等待文件生成、等待变量满足条件。我把所有固定延时都换成了条件等待。调度这块我直接在计划任务节点里设置了每天的触发时间。这里有个容易忽略的点执行任务的那台 Windows 机器不能休眠不能锁屏后自动断开网络。我把电源计划改成了“从不睡眠”并把 1949 的调度服务设为开机自启。失败重试的策略是整体流程最多重跑 3 次每次间隔 5 分钟。如果第三次仍然失败就触发异常通知节点把失败截图和日志发到值班群。这里的截图是 1949 自动抓取的不需要额外写代码很省心。数据校验也加上了。我在读取表格后立刻判断行数如果为 0 就标记为异常不继续执行导出和发送。这个设计避免了一个很坑的情况流程显示“成功”但数据是空的群里照样收到一封带着空表格的通知。3.4 第四步新旧方案并行验证再平滑切换切换过程我没有一刀切。旧 Selenium 脚本和新 1949 流程并行跑了整整两周。每天早上旧脚本正常产出新流程也同时跑但新流程的输出文件放到一个单独的验证目录不直接发给业务同事。每天上午我会对比两份产出的文件核对行数、关键字段、文件大小、生成时间。前三天就发现了一个差异1949 流程跑出来的表格比旧脚本少了两行原因是旧脚本的分页逻辑漏掉了最后一页而这个问题从来没被发现过。数值型字段也因为浮点格式化差异产生了小数点后两位的精度问题。这些差异如果不并行验证直接切换之后根本不会意识到。连续 10 个工作日确认无误后我才把旧脚本停掉。又过了三天才把服务器上的 Python 环境和 ChromeDriver 清理掉。这里我的建议是不要急着销毁旧环境留一个备份至少留一两个星期给自己留退路。4. 真实成本账钱、时间、维护和隐性成本4.1 按时间成本算一笔账很多人一听说可视化编程第一反应是“是不是不用写代码了”。这句话我只能信一半。不用写的是浏览器操作的代码但流程设计、异常分支、参数配置、数据校验这些功夫一点也不少。不过我实际跑下来新版的重构成本确实比旧版低很多。成本项Selenium 旧方案1949 新方案初始开发投入约 3 人天包括调试登录、分页、无头模式、环境搭建约 0.5 人天包括软件安装、流程搭建、并行验证每周例行维护平均 1.5 小时主要是页面改版排查平均 0.3 小时偶尔调整等待条件单次故障恢复40 分钟起步经常要重新定位元素10 分钟左右靠日志和截图定位人员技能要求需要 Python、Selenium、XPath/CSS、浏览器驱动知识看得懂流程图、会录制操作即可运行基础设施一台能跑 Python Chrome 的服务器依赖多一台 Windows 办公机即可调度器自带异常可观测性默认静默失败需要自建日志和告警自带流程日志、节点耗时、失败截图、重试和通知按人力成本粗算假设一位熟练工程师的月成本按 15000 元算工作日 21 天每小时成本约 89 元。旧方案首次开发 3 人天大约是 2136 元新方案 0.5 人天大约是 356 元。旧方案每周维护 1.5 小时一年 52 周就是 78 小时约 6942 元新方案每周 0.3 小时一年 15.6 小时约 1388 元。单纯维护费每年差 5500 元左右三年下来差将近两万。这还没算每次故障导致业务等待的时间成本。4.2 按稳定性和可交接算一笔账但我觉得真正值钱的不是这点维护费而是两件很难量化的事稳定性和可交接性。旧脚本的稳定性说白了取决于页面不变化。新流程的稳定性取决于异常分支和重试策略。同样一次页面局部改版旧脚本可能要花 40 分钟改代码新流程可能只要重新录制一个点击节点再对一下数据集字段就完事。这个差别只有经历过“早上报表没出全业务群都在问”的人才能体会。可交接性就更明显了。旧脚本放在那里不懂 Python 的同事只能干瞪眼。新流程就是一张节点图谁打开都能看懂“先登录、再查数、再校验、再发群”。后来团队里另一位同事接手只花半小时熟悉界面就开始独立修改导出节点里的文件命名规则。这在以前是想都不敢想的。注意可交接不等于免维护。流程图再直观也必须有文档写明触发时间、前置条件、输出位置、异常联系人。我单独建了一个 markdown 文件放在流程模板同目录下每次改流程就顺手更新文档。4.3 并没有省钱的部分成本账不能只算好的方面。以下是新版方案并没有省钱的部分说清楚免得带偏别人。第一1949 本身有授权成本虽然不是每月烧钱但这是一笔不会消失的固定支出。第二可视化流程同样需要维护页面改版了要重新录制、字段变了要重新映射、等待条件不合适要调参数。第三复杂度是有天花板的。如果某个流程的分支超过十几条数据变换又特别复杂图的可读性会明显下降。这种情况应该拆成多个子流程或者把复杂计算丢回给代码。第四任何自动化都需要有人定期检查哪怕流程连续一个月没出错你也要每周扫一眼日志确认它真的在跑、真的在按预期产出。5. 常见问题与排查技巧我踩过的坑5.1 流程比脚本慢怎么办新版流程第一次跑的时候耗时竟然比 Selenium 还慢原因是每个节点都默认截图留痕。截图越多执行时间越长。解决办法是把截图策略改成“仅失败时截图”并在关键节点保留页面跳转截图。等待条件也要从固定延时改成条件等待。优化之后整个流程从平均 4 分 20 秒降到了 3 分 10 秒。另外一个常见慢点是流程里用了大量“等待固定秒数”的节点。很多人在页面上加了sleep(3)就以为万事大吉实际上一旦网络变慢3 秒根本不够网络快的时候又是白白等待。正确做法是等元素出现、等文本变化、等文件生成让流程自己判断何时继续。5.2 页面元素总是识别不到页面元素识别不到多半是这三个原因iframe 嵌套、shodow DOM、元素属性动态变化。旧脚本遇到 iframe 还要切 frame遇到 shadow DOM 几乎束手无策。1949 里的处理方式是用完整元素路径或者在录制阶段让它自己去解析层级。我踩得最多的是动态 class。前端框架每次渲染都会生成一串随机 class 名录制时能定位下次运行就失效。解决办法是不依赖 class优先用稳定 ID、name、文本内容、或者相对位置关系。真的遇到实在定位不到的元素我建议换一条操作路径比如把“点击按钮”改成“按 Tab 键切换焦点 按 Enter 确认”这样绕开按钮的动态属性实测下来非常稳。5.3 定时任务不触发或重复触发定时任务不触发十有八九是机器休眠了。我一开始用的是普通办公电脑下班后系统进入睡眠第二天早上调度器根本醒不过来。解决方法是在电源计划里把“睡眠”改成“从不”并关闭快速启动。另外还要确认 1949 的调度服务是不是开机自启了否则机器重启后任务就不再执行。重复触发是另一个坑。新版流程第一次跑的时候上一个流程还没结束下一个触发点又到了结果两个流程同时对同一批数据操作产生了重复报表。解决办法是打开调度器的并发控制开关或者在流程开头加一个互斥锁节点执行前写一个标记文件执行结束后删除。如果发现标记文件已存在就直接跳过本次执行。5.4 数据抓漏或对不上数据抓漏很大一部分原因是页面加载是分批渲染的表格先显示前面几十行滚动到底部才加载更多。如果流程没有等到底部数据加载完就读取就会少数据。我的处理方式是在所有分页或滚动加载的页面先设置一个“等待数据加载完成”的判据比如某个计数文本从“共 100 条”变成实际总数然后再读取表格。新旧数据对不上还有一个隐蔽原因浮点精度。系统页面上显示的是两位小数接口或导出文件里可能是原始浮点数。写入报表时如果格式化方式不一致出来的数字就会差一点点。解决办法是在流程里加一个数值格式化节点所有数字统一保留两位小数并在并行验证阶段把新旧两个文件的数字逐行比对。5.5 团队里有人把流程改坏了流程可视化之后团队里能看懂不代表能随便改。我遇过一次同事想改一下邮件标题结果不小心把“等待元素出现”节点删了整个流程跑了十分钟后全部失败。后来我定了规矩修改流程前先复制模板到“草稿”目录在草稿上改验证通过再发布到正式目录。同时每次修改都要在流程备注里写明变更内容、修改时间、修改原因。这个习惯一开始有点麻烦但在多人协作场景下特别值。它让流程演进的每一步都有记录出了问题也能快速定位是哪个节点被动了。6. 这次重构之后我的一些后续想法和真实体会流程跑稳定之后我没有停下来。下一步我打算把部分页面抓取改成 API 请求节点因为接口拿数据的稳定性比页面解析高得多。然后把“每日报表”拆成“数据抓取、数据质检、结果分发”三个独立的子流程这样就算报表 A 挂了报表 B 也不会受影响。这次从 Selenium 到可视化编程的重构给我的真实体会是自动化的重点从来不是“会不会写代码”而是“出问题之后多久能发现、多久能解决、谁都能接手”。Selenium 不是不好它的灵活性和生态无可替代但它的维护成本对一个小团队来说还是太高了。1949 这种轻量级自动化工具胜在把高频操作场景的维护成本拉低了一个量级让流程真正变成团队资产而不是某个人脑中的孤岛知识。如果你现在还在用脚本硬扛频繁改版的页面我的建议是别急着直接上重型 RPA。先把自己手头的任务画一张操作地图把触发时间、输入输出、异常分支列出来再算一笔时间账看看每次改版和故障修复到底花了多少人力。算完这笔账选型的答案大概率会清晰起来。