网页改版之后,最容易出现一种错觉:页面还能手工点通,自动化流程就不算坏。实际上,手工成功只证明人找到了新的路,不证明流程已经重新认识这条路。人可以凭视觉判断哪个是模型下拉框,等一会儿再看主体标签,也可以临时找到上传入口;脚本只能按它保存下来的契约行动。
这次遇到的就是这种情况。原本已经准备好的台词、提示词、音色、参考图和身份信息,卡在网页上的几个动作:模型选不上,参考图上传不稳定,提交动作和旧版不同。表面上看,是网页变了;真正要处理的,是本地流程保存的假设,和线上此刻的实况不再一致。
网页改版后的首要任务,不是马上重写自动化,而是先确认哪些契约真的失配。
人能点通,不等于流程已经修好
当时最直观的表现,是模型选择器找不到原来的文字。旧流程把某个模型名称当成了固定锚点,但新版页面打开后,默认选中的模型可能已经换成另一个选项。人看见下拉框仍然在那里,点开、浏览、选择都没有困难;脚本却在等待一个已经不再出现在折叠标签里的文本。
这类问题很容易被误判成“网页整体不可用了”。如果不拆开看,维护者可能从导航、页面入口到提交流程全部重做,既浪费时间,也可能把原来稳定的能力一起改坏。更危险的是,重写之后只手工成功一次,大家就以为自动化已经恢复,下一次换模型或换输入时,旧问题又会回来。
所以我先把问题限定为活体探测:当前页面有哪些控件,默认值是什么,上传入口是否存在,提交按钮如何触发,异步结果什么时候才算真的出现。这个顺序很重要,因为它把“我觉得网页改了”变成了“哪一层契约发生了变化”。
先区分稳定契约和易变信息
活体探测时,我没有把页面上看见的每一项都当成需要落盘的事实。比如首页促销横幅里的价格和折扣,可能随时间、账号状态或活动变化。它可以作为当次预检的提示,却不适合成为自动化流程的稳定基线。
这里最容易误判:看见一个新价格,就顺手去改价格配置;看见下拉里增加了几个模型,就认为本地模型能力表也一定缺项。实际核对后,新出现的模型已经在本地能力清单中,真正失配的是默认选项对应的文字锚点,而不是模型能力本身。
稳定契约应该描述“怎样找到并操作控件”,易变信息则应该交给每次运行时的活体预检。
这个区分让修复范围一下子变小。顶部导航、资产卡、记录卡和取数通道仍然正常,就不需要跟着网页更新一起改。模型下拉新增选项,也不代表要重写模型目录。只有确实影响动作的失配锚点,才进入修复清单。
把一个故障拆成几层失配
继续往下排查后,我发现这不是一个单点故障。第一层是模型选择:默认模型改变,使依赖固定文本的选择器失配。第二层是上传:参考区的添加槽变成了常驻的界面元素,页面不再提供旧流程期待的文件输入框,点击之后还可能走系统文件选择接口。
第三层是提交:新版页面不一定接受按 Enter,真正的提交动作需要点击发送按钮。第四层是异步状态:选择已经保存的主体后,标签不会立刻出现在页面上,脚本如果只等待很短时间就读取结果,会把“还没渲染完成”误判成“选择失败”。
这几层看起来都像“按钮找不到”,但修法完全不同。模型层需要调整锚点,上传层需要复用能够接住新触发方式的上传通道,提交层需要匹配新的发送动作,异步层需要增加有界轮询。把它们混成一个大补丁,后续很难知道是哪一层真正恢复了。
增量修复的最小单位不是一个页面,而是一条具体的失配契约。
我选择按层修复,是因为每一层都有自己的证据和回归范围。模型选择成功,不代表参考图已经进入页面;参考图出现缩略图,也不代表提交动作正确;预检显示可以提交,更不代表整条流程在失败后能清理现场。只有拆开,才不会用一个偶然成功掩盖另一个仍未修好的环节。
上传通道不能只看旧的输入框
参考图问题尤其容易把人带偏。旧流程习惯寻找文件输入框,然后把路径交给页面。新版页面的添加槽常驻在参考区,点击后由浏览器的文件访问能力接管,单纯拦截输入框点击自然不会生效。
如果不处理,包含引用图片的提示词会在提交前直接失败。页面并不是不允许提交,而是提示词里的图片引用还没有对应的已上传对象。此时人手动上传一张图,可能立刻成功,于是问题被归因于“脚本偶尔不稳定”;实际上,自动化根本没有走到页面自己的上传管线。
我没有为数字人、图片和视频各写一套新的上传实现,而是把它们接到同一条原生上传通道,同时保留旧输入框存在时的兼容路径。这样做的理由很直接:上传的目标都是让页面确认文件已经进入自己的状态管理,差别只在触发入口。共享通道可以集中处理点击、文件选择和新式选择器,消费方只负责定位当前要填的槽位。
这也带来一个必要的边界:空编辑器里没有参考态时,不应该为了“验证完整”强行制造一个不存在的删除控件。只读探测发现没有这个元素,就把它记录为当前状态的差异,而不是把空态当成漂移。维护自动化时,先判断状态,再判断控件,比把所有页面都想象成同一种初始状态更可靠。
提交动作和等待时间都要有证据
提交方式的变化说明,键盘动作不能被当成永远稳定的快捷键。新版流程要求点击发送按钮,而不是依赖 Enter。这个改动看起来只差一个动作,但影响的是整条任务的终点。如果脚本把提示词填好后按 Enter,页面可能只是换行,或者什么都不做;如果随后代码把“没有新记录”当成渲染失败,就会继续重试,反而制造重复任务的风险。
异步主体也是同样的道理。选择主体后,页面需要一点时间把标签写回界面。原先固定等待很短时间,在旧版页面上可能足够;新版水合和渲染顺序变化后,就会出现已经选中、但读取时还没显示的中间状态。我选择有界轮询,而不是无限等待,是因为流程既要给页面完成更新的机会,也要在真实失败时尽快停下并留下证据。
如果不处理这些边界,最坏的结果不是一次报错,而是错误重试、重复提交和难以对账。可靠的自动化不是把等待时间写得更长,而是等待一个可观察的状态,并为超时规定停止方式。
健康检查不能被一次成功替代
修复之后,我把验证分成几道门。先跑只读健康检查,确认模型锚点、上传状态、提交触发和关键取数通道仍能被发现;再跑回归用例,确保旧的选择器、清理逻辑和错误处理没有被新路径破坏;最后才做一次低成本的真实提交,验证从准备到平台接受之间没有断点。
这里的关键不是检查数量,而是每道检查回答不同的问题。健康检查回答“页面现在长什么样”;回归用例回答“原来已有的能力还在不在”;真实提交回答“这套判断能不能穿过真实边界”。只做其中一项,结论都会有盲区。
这次还暴露出一个容易忽略的配套问题:失败的预检如果留下半加载的任务空间,下一次复用同名空间就可能在错误现场继续判断。于是清理动作必须放在失败路径也能执行的位置,模式切换和状态读取也要有界。自动化系统真正的稳定性,经常藏在失败之后有没有恢复干净,而不是顺利时点得有多快。
下次我会怎么做
下次遇到网页改版,我会先做一份只读活体记录:页面入口、关键控件、默认值、上传前置条件、提交触发方式和异步回执。然后把变化分成3类:稳定契约变化、易变展示变化、暂时无法确认的状态。稳定契约才进入代码修复,易变信息留给运行时探测,未知项则明确标记,不靠猜测填平。
接着,我会沿着“定位、上传、提交、取回、清理”逐层比对本地合同与线上实况。每发现一处失配,只改对应锚点或通道,并立刻跑这一层的最小回归。这样既保留原有能力,也能让每次改动都有清楚的因果关系。
最后,我会把健康检查、回归用例和一次低成本真实提交作为完整闭环。手工能点通,只能说明人找到了路;自动化真正修好,则意味着下一次换默认值、换上传入口或遇到异步延迟时,流程仍然知道该观察什么、何时停止、失败后怎样恢复。
一个流程成熟的标志,不是它能在今天跑通一次,而是网页明天变化时,我们仍然只需要修失配的那一层。