我从第一次把 UI.Vision RPA 装进浏览器,到今天已经用它跑过好几千次循环,中间删掉的脚本比留下的多得多。这个工具最容易被误解的地方在于,很多人把它当成"录制一下就完事"的傻瓜软件,装完点两下发现某个页面死活点不中,就断定它不行。实际上它是一套有明确分层设计的自动化工具:浏览器扩展负责页面理解和指令编排,本地执行组件负责接管鼠标键盘和文件对话框,命令行参数负责让它脱离人工点击自己跑起来。这三层里任何一层没配好,脚本就会在你面前表演"看起来在跑,其实什么也没做"。
这篇内容适合三类人看:手上有一堆固定网页操作要重复做、又不想学一整套编程框架的人;已经会用脚本但懒得为每个小任务都搭一遍环境的人;以及用过 UI.Vision RPA 但卡在图像识别或者定时调度上、想搞清楚到底哪里出问题的人。下面这些东西都是我在真实任务里反复验证过的,包括配置、命令写法、阈值调整和一堆踩坑记录,你基本可以照着抄。
1. 一个浏览器扩展凭什么被塞进自动化工具箱
1.1 它真正吃掉的是哪一段重复劳动
先把这个工具的定位说清楚:它不是万能的桌面自动化,也不是纯粹的网页爬虫框架,它最擅长的是"人在浏览器里做的、有固定顺序的、每次差别不大的操作"。登录后台、按条件筛选、导出报表、把几个系统的数据对着填、定时检查某个页面上的数字有没有变化——这类活的共同点是步骤明确但数量多,而且往往分散在一天里的固定时间点。
手工做这类事最消耗的不是时间,是注意力。你得盯着加载转圈、等弹窗、确认保存成功,中间被打断一次就要重新找回位置。UI.Vision RPA 的价值就在于把这段"注意力占用"换成"机器等待"。它内置了等待类命令,能一直等到某个元素出现再往下走,而不是傻等固定秒数。这一点比很多人自己写的脚本还靠谱,因为固定 sleep 写短了会失败、写长了整批任务时间被拖垮。
我见过最常见的失败案例,是把工具当成"什么都能自动化"的锤子,结果去啃需要登录态校验、强验证码、复杂文件解析的硬骨头,最后得出结论说这工具不行。判断标准其实很简单:如果你自己坐在电脑前,能用固定的十几个动作完成这件事,那它八成能搞定;如果每次操作路径都不一样、需要你临场判断,那就不适合。
1.2 脚本派与录制派的分界线在哪
自动化这件事大致分成两派。一派是代码派,用 Selenium、Playwright 这类库,能力强、可控性高,代价是要搭环境、要会写选择器、要处理等待和异常。另一派是录制派,像按键录制、界面点击录制,门槛极低但脆得像纸,页面改一个 class 名就全线崩盘。
UI.Vision RPA 站的位置比较有意思,它是录制派的外壳加脚本派的内核。表面上看你在界面上点一下它记一条,实际上每条记录都是一条独立的命令,可以手改、可以插入循环、可以调用 JavaScript 表达式算值。也就是说你完全可以从录制起步,然后逐条把脆弱的部分替换成更稳的写法。这个"渐进式加固"的路径,是我认为它比纯录制工具更值得投入时间的关键。
分界线在于你怎么对待录制产物。新手往往录完直接跑,跑通一次就当成资产;有经验的人会把录制结果当草稿,先看清楚它生成的定位方式是什么,再决定哪些留着、哪些必须换掉。后面第 3 节会详细讲这个改造过程,这里先给你一个判断原则:凡是靠"第几个按钮"或者"坐标位置"定位的,都不算稳定资产。
1.3 免费开源的边界:哪些功能真的不要钱
这一点必须提前讲清楚,否则你会在做到一半的时候突然撞墙。UI.Vision RPA 的浏览器扩展部分代码是公开的,你可以自由查看、修改、二次分发;但它配套的本地执行组件(负责屏幕级点击、键盘输入、读取本地文件的那部分)是免费提供但不开源的,部分高级能力还需要付费授权。
对绝大多数日常任务来说,免费范围已经够用:页面内的点击、输入、选择、文本提取、条件判断、循环、CSV 读写、图像匹配、截图,这些都不需要付费。真正会碰到边界的场景通常是:需要大量图像识别的复杂桌面流程、需要在多台机器上集中管理调度、需要更细的 OCR 参数控制。我的建议是先按免费范围把流程跑通,跑通之后再评估瓶颈到底在不在付费功能上,别一上来就买授权结果发现根本用不到。
| 能力类型 | 免费范围 | 说明 |
|---|---|---|
| 页面元素操作 | 支持 | 点击、输入、下拉选择、文本提取 |
| 流程控制 | 支持 | 条件判断、循环、子流程调用 |
| CSV 数据驱动 | 支持 | 按行读取、写回结果 |
| 图像匹配 | 支持 | 有次数和场景上的实际限制 |
| 本地键鼠接管 | 免费组件 | 需额外安装本地执行组件 |
| 集中调度管理 | 部分需授权 | 单机自用基本用不到 |
我把这张表放在前面,是因为很多人对"免费开源"四个字有过度期待,以为连企业级调度都白送。把预期摆正,后面的学习曲线会平缓很多。
2. 安装环节藏着的三个隐形前提
2.1 扩展本体和本地执行组件不是一回事
新手最容易犯的错,是以为在浏览器商店里点一下"添加至浏览器"就装完了。扩展装好只能做页面内的操作,一旦流程里出现"点开系统文件选择框选一个文件""在桌面某个位置点一下""读取本地某个目录里的图片做匹配",就必须有本地执行组件在后台待命。
这个组件的安装方式通常是一个独立的安装包,装完之后扩展会自动检测到它,界面上原本灰掉的命令会变亮。判断有没有装好有个很直接的办法:打开工具的设置页,看本地连接状态是不是正常;或者直接跑一条屏幕级点击命令,看它有没有报"找不到本地组件"。我建议在正式做任务之前先跑这个最小验证,别等到写了八十行才发现底层压根没通。
另一个隐性前提是浏览器版本。扩展依赖浏览器提供的一些接口,版本太老会导致部分命令不可用,版本太新(尤其是刚推送的大版本)偶尔会出现兼容性抖动。我的习惯是:主力机器上保持浏览器在一个相对稳定的版本,不要开自动更新;测试机可以随便升,用来提前发现兼容问题。
2.2 浏览器策略与权限的常见拦路虎
如果你用的是自己私人电脑,这一步基本不会碰到问题。但只要涉及到单位统一管理的设备,就可能遇到策略限制:扩展被禁止安装、扩展被允许安装但不许访问特定站点、本地组件被安全软件拦下来。这类问题的表现往往很迷惑——扩展图标在,点开也能用,就是一执行就无声失败。
排查顺序我一般是这样的:先看扩展详情页里的"站点访问权限"是不是设成了"点击时"而不是"在所有网站上",这个设置会让脚本在后台页面直接失效;再看浏览器有没有开启"增强保护"之类的拦截模式;最后确认本地组件是不是被杀毒软件隔离了。第三条最坑,因为隔离往往是静默的,你只会看到命令超时。
还有一个容易被忽略的点:无痕窗口。默认情况下扩展在无痕模式下是不启用的,如果你的脚本需要干净环境(比如每次都从登出状态开始),要么手动在扩展详情里打开"在无痕模式下允许",要么干脆用独立的浏览器配置文件来跑。后者更稳,因为配置文件之间互不干扰,登录态、缓存、下载目录都能隔离。
2.3 固定版本比追新更省心
这条经验是用血换来的。浏览器扩展有个特点:它会自动更新,而且更新不通知你。某天早上你发现昨天还跑得好好的脚本今天集体失败,排查半天发现是扩展版本变了,某条命令的默认行为改了。
应对办法有两个方向。稳妥派的做法是把扩展目录整个备份出来,用开发者模式加载本地副本,这样更新不会自动覆盖你;代价是要手动维护更新。省事派的做法是不动扩展,但把所有关键脚本在版本更新后跑一遍回归测试,发现问题及时改。我自己的做法是混合的:核心生产脚本配一套固定的本地副本,试验性脚本走商店版本,两边隔离。
顺便提一句浏览器本身的自动更新。浏览器升级导致图像识别偏移、坐标错位的情况我遇到过不止一次,原因通常是渲染细节或者默认缩放比例变了。如果你的流程严重依赖图像匹配,关掉浏览器自动更新能省掉大量莫名其妙的排查时间。
3. 录制出来的东西只能算草稿:改造脚本的四个动作
3.1 先读懂录制产物的结构
宏文件本质是一个结构化文本,可视化编辑器里看到的一行行命令,对应文件里的一个数组,每条记录包含命令名、目标、值、描述四个字段。理解这个结构很重要,因为你要做的手工修改很多时候是在文本层面完成的,比如批量替换定位方式、批量插入等待。
{ "Name": "weekly_export", "Commands": [ { "Command": "open", "Target": "https://example.com/report", "Value": "" }, { "Command": "type", "Target": "id=username", "Value": "${user}" }, { "Command": "click", "Target": "id=submit", "Value": "" }, { "Command": "waitForElementPresent", "Target": "css=table.data", "Value": "30000" } ] }这段结构里最值得关注的是 Target 字段,它就是定位器。录制工具自动生成的定位器,优先级通常是:能拿到 id 就用 id,拿不到就用一串层级很深的选择路径,再拿不到就用坐标。层级路径和坐标都是定时炸弹,页面加个广告位、调一下布局就失效。所以拿到录制结果的第一件事,是把每一行的 Target 挨个看一遍,标出哪些是"脆弱定位"。
我的习惯是打开浏览器的开发者工具,对着每个关键元素手动确认一遍有没有稳定的标识。如果有稳定的 id 或者带语义的文本,就用它;如果什么都没有,就考虑用图像定位或者相对文本定位兜底。这一步花的时间,会在后面几十次运行里成倍赚回来。
3.2 定位器优先级:id、文本、图像怎么排
这部分是整套方法里最影响成败的。我按稳定性从高到低排了一个顺序,你可以在改造时直接照着选。
第一优先是稳定的唯一标识。元素上如果有不会随内容变化、不会随版本迭代改名的 id 或者属性,用它最省事,速度也快。注意要区分"看起来像 id"和"真的稳定",有些系统会给 id 拼上随机串,那种等于没有。
第二优先是语义文本。按钮上写着"导出报表",这个文本在业务逻辑不变的前提下通常也不会变。用文本定位的好处是可读性极强,脚本放在那儿半年后你还能一眼看懂它在点哪里。坏处是遇到多语言切换或者文本里带空格换行会失配,需要做容错。
第三优先是结构路径。只有在上面两种都没有的时候才用,而且要尽量写短,不要直接复制一长串从 html 开始的路径。路径越长,中间任何一层变动都会导致整条失效。
第四优先才是图像。图像匹配是最后的兜底手段,因为它依赖渲染结果,受分辨率、缩放、主题色、字体渲染影响。它非常适合处理画布类应用、视频控件、无 DOM 语义的老系统,但绝不该用在明明有稳定 id 的普通按钮上。
| 定位方式 | 稳定性 | 执行速度 | 适用场景 |
|---|---|---|---|
| 唯一 id 或稳定属性 | 高 | 快 | 规范化后台系统 |
| 语义文本 | 中高 | 中 | 按钮、菜单、提示语 |
| 结构路径 | 中低 | 中 | 无其他可用标识时 |
| 图像匹配 | 中 | 慢 | 画布、无 DOM 场景 |
3.3 变量、循环、条件判断的最小可用写法
能录制只能说明你会用鼠标,会用变量和循环才算真正入门。这里我讲三个必须掌握的最小单元,掌握了它们,脚本的表达能力会有质变。
变量赋值和引用。绝大多数命令的 Value 字段都支持变量替换,写法是美元符号加大括号包住变量名。内置变量以感叹号开头,比如循环序号、当前行号,自定义变量随便起名但要避免和内置冲突。我习惯在脚本开头集中声明所有外部输入,这样换环境只需要改开头几行。
循环。按次数循环用成对的起止命令包住中间段落,循环体内可以拿到当前序号。按行遍历 CSV 是另一套:把读取行号变量设成 1,然后每轮读完自增,直到读到空行退出。这套写法用来做批量填表特别顺手,把数据准备在表格里,脚本只管按行消费。
条件判断。成对的条件命令包住分支段落,条件里可以直接写表达式比较。用它的典型场景是处理"成功提示"和"错误提示"二选一:先等两个提示任意一个出现,再判断出现的是哪个,走不同分支。这一招能把一大批"跑十次失败三次"的脚本变成稳定运行。
提示:条件判断里比较空值时,注意区分"变量不存在"和"变量存在但为空",这两种情况在很多脚本引擎里行为不同。我一般会先用一条赋值命令给变量兜个默认值,再参与判断,避免踩这个坑。
3.4 把"能跑"改成"跑一百次还对"
录制产物改完之后,第一遍跑通只是及格线。真正决定它能不能当资产用的是接下来这几件事:把每一处固定等待换成条件等待,把每一个可能失败的步骤加上失败后的处理路径,把每一步的关键结果写进日志。
固定等待换成条件等待是最立竿见影的优化。工具提供了等待某元素出现、等待文本出现这类命令,第三个字段就是超时毫秒数,超时后可以选择报错或者继续。用它的好处是快页面不会浪费时间、慢页面不会提前扑空。我在实际任务里把几十个固定等待全部替换掉之后,整批任务的耗时下降了差不多四成,失败率也降了。
日志这件事很多人不做,做完之后你会发现排查效率完全不一样。最简单的做法是每一步之后把关键状态追加写入一个文本文件,格式带上时间戳、步骤名、结果。出问题的时候不用重跑,直接翻日志就能定位到第几步开始不对。
4. 页面结构靠不住的时候:图像匹配与OCR的实战边界
4.1 图像匹配的相似度阈值与截图规范
图像匹配的原理不复杂:把你提供的样图,在屏幕上按像素滑动比对,找到相似度超过阈值的位置,然后点下去。难的是把这个阈值调对。调太高,页面上一点细微渲染差异就匹配不上;调太低,页面上有一堆相似的图标就会点错地方。
我的经验值是这样的:清晰、独一无二、带文字的按钮图标,阈值可以设到 0.8 以上;纯色块或者线条构成的极简图标,因为区分度低,建议 0.7 左右并配合区域限定;如果需要容忍主题切换带来的色差,可以再降,但降到 0.6 以下基本等于碰运气。
截图本身的质量决定了一半的成功率。截的时候有几个讲究:只截必要的局部,不要带上一大片背景,背景越多干扰越大;避开有动态内容的区域,比如带倒计时的按钮、会变色的状态标签;尽量包含一点点固定特征,比如按钮边缘的圆角或者固定图标,帮助算法区分;不要在放大或缩小的浏览器状态下截图,一定要在脚本运行时使用的那个缩放比例下截。
还有一个细节:截图保存下来的文件名要有意义。我见过一个脚本里全是1.png、2.png,三个月后连作者自己都不知道哪个是哪个。改成btn_export_report.png这种命名,维护成本立刻降下来。
4.2 DPI、缩放与多屏环境下的坐标陷阱
这是图像识别类工具最容易翻车的地方,也是论坛里问得最多的问题:同一套脚本,在你机器上跑得好好的,换台电脑就全乱。原因通常在三处。
系统显示缩放比例不同。笔记本默认 125% 或者 150% 缩放,外接显示器可能是 100%,浏览器渲染出来的像素尺寸完全不一样,之前截的图自然匹配不上。解决办法是在目标机器上重新截图,或者把运行环境的缩放统一固定。
浏览器缩放不同。这个更隐蔽,因为很多人忘了自己曾经按过快捷键放大网页。检查办法很简单,看一眼地址栏右侧的缩放百分比是不是 100%。脚本里也可以主动设置成固定值,避免人工操作带来的漂移。
多显示器坐标偏移。屏幕级点击用的是绝对坐标,如果你的第二块屏幕在左边或者在上方,坐标系原点就不是左上角,之前在主屏上跑通的坐标会整体偏移。稳妥的做法是让脚本只在主屏运行,或者运行前先把目标窗口挪到固定位置。我自己的做法是干脆把副屏关掉再跑批处理任务,省去所有麻烦。
4.3 OCR能读什么、读不了什么
文字识别在自动化里是个很有用的补充,特别是面对那些把数字渲染成图片的老系统,或者需要从截图里提取金额、单号的场景。但它有明确的舒适区和禁区。
舒适区是:白底黑字、字体规范、字号不小、排列规整的区域。比如表格里的一列数字、一张票据上的关键字段、页面角落里的一串编码。这类内容识别准确率相当高,配合简单的后处理(去空格、去换行、数字校验)基本可以直接用。
禁区是:低分辨率、彩色背景、艺术字体、文字和背景对比度低、文字倾斜或者有遮挡的场景。这些情况识别结果会掺进大量噪声,你会为了清洗结果写一堆补丁,最后还不如换个思路。
我的实际用法是把它当"辅助校验"而不是"主数据源"。主数据还是从页面元素里取,OCR 用来做交叉验证:比如导出报表后识别一下页面上的总条数,跟 CSV 行数比一下,对不上就报错。这种用法对准确率要求没那么苛刻,但能挡住一大类"看起来成功其实导错了"的沉默故障。
5. 让宏脱离浏览器界面自己跑:命令行与调度
5.1 direct 参数直启宏的用法
脚本调试好了,下一步是让它不用你点。这个工具提供了一个比较朴素但好用的机制:通过命令行打开一个特定的本地页面,并在地址里带上参数,让它直接执行指定名称的宏,跑完自动关闭。
# 示例:通过命令行直启宏并自动关闭标签页 "chrome.exe" \ --profile-directory="Default" \ "file:///C:/vision/ui.vision.html?direct=1¯o=weekly_export&close=1"这里的几个参数含义大致是:直启标记让它跳过欢迎界面,宏名称参数指定跑哪一套,关闭标记让执行完自动收尾。需要提醒的是,不同版本对参数的支持不完全一致,有些版本改过文件名或者参数名,所以第一次配的时候一定要实际跑一遍验证,别直接照抄到生产环境。
另一个要注意的点是浏览器配置文件。命令行里如果不指定配置文件,打开的可能是一个全新的匿名环境,登录态都没有,脚本第一屏就卡在登录页。指定成你平时用的配置文件,或者干脆专门建一个自动化用的配置文件预先登录好,二选一都行,但必须明确。
5.2 计划任务里的环境变量与工作目录
要让脚本按点跑,通常用系统自带的任务计划功能。这里有两个坑,几乎每个人第一次配都会踩。
第一个是工作目录。脚本里引用相对路径的文件(比如样图、CSV 输入),是相对于"当前工作目录"去找的,不是相对于脚本文件位置。计划任务默认的工作目录往往是系统目录,结果就是脚本在编辑器里跑得好好的,从计划任务启动就报"文件找不到"。解决办法是在任务配置里显式指定起始目录,或者干脆在脚本里全部改用绝对路径。
第二个是环境变量和用户会话。图形界面相关的操作需要一个已经登录的桌面会话,如果任务设成"用户未登录时运行",涉及到本地键鼠的命令会直接失败。这个失败很讨厌,因为它不报错,只是什么都不做。所以涉及到屏幕级操作的任务,务必设成"仅在用户登录时运行"。
还有一个配套设置:任务的"停止现有实例"选项。如果你的脚本执行时间可能超过触发间隔,前一次还没跑完下一次又启动了,两个实例抢同一个浏览器窗口,结果一团糟。要么设成不重复启动,要么在脚本开头加一段检测锁文件的逻辑。
5.3 日志、退出码与失败重试怎么设计
无人值守的脚本,唯一的健康指标就是日志。我在每个正式任务的脚本里都会做三件事。
第一,开头写一条启动记录,带上时间、机器标识、版本号。这样翻日志的时候能立刻知道是哪台机器哪一次。
第二,每个关键节点写一条进度记录。不用太细,通常记录"进到哪个页面""取到多少条数据""导出文件叫什么名字"就够了。出问题时按时间线一拉,立刻定位到断点。
第三,结尾写一条汇总记录,包含成功条数、失败条数、耗时。这条记录我还会同时追加到一个汇总文件里,方便做长期趋势观察——比如某天开始失败率突然升高,往往意味着对方页面改版了。
重试策略要分级。网络抖动类的失败,重试两三次基本能过;元素找不到类的失败,重试往往也是白搭,不如直接报警让人看。我的做法是在脚本里对"等待超时"这类可恢复错误做三次重试,对其他错误直接跳到收尾并标记失败,绝不无限重试,因为无限重试会把一个明摆着的问题拖成一周后才发现。
6. 跑了几十次才会撞上的五类故障与排查链路
6.1 加载时机与"太快了"型失败
这类失败的表现非常固定:手动跑没问题,无人值守跑就失败;或者连续跑十次,中间随机失败一两次。原因几乎都是执行速度比页面响应快。
排查链路我是这么走的:先看日志里最后一条成功记录停在哪一步,确定断点;然后把这一步前后的命令加上临时截图,重跑一次看看到底页面长什么样;十有八九会看到页面还停在加载中,或者关键元素还没渲染出来。
修复方式就是替换成条件等待。等待目标元素可见,超时设长一点(我一般给 30 秒),超时后走失败分支而不是干等。有些页面会有骨架屏,元素存在但内容没填,这种情况要等的不是元素存在而是文本出现,得用等待文本类命令。
还有一个更隐蔽的变体:元素已经出现了,但被一个透明遮罩盖住,点击落到了遮罩上。这种失败表现是"命令执行成功但页面没反应"。处理办法是等遮罩消失再点,或者点完之后断言预期结果是否出现,把静默失败变成显式失败。
6.2 iframe、弹窗与文件对话框
三种"页面里的页面",处理方式完全不同。
iframe 是嵌在页面里的另一个文档。页面级的选择器默认进不去,需要先切换到目标框架再操作,操作完切回来。较新版本提供了显式的框架切换命令,老版本如果没有,就只能靠图像识别或者坐标点击绕过。我遇到过一层套三层的嵌套框架,最后放弃了选择器,直接改用图像定位,反而更省事。
弹窗分两种。浏览器原生弹窗(那种带确定取消的对话框)不能当普通页面元素处理,需要专门的确认命令;网页里模拟出来的弹窗就是普通元素,正常点即可。判断方法是看它能不能被开发者工具选中,选不中的就是原生弹窗。
文件对话框是本地组件的主场。点击上传按钮后弹出的系统选择框,页面层完全碰不到。正确做法是先点开对话框,然后用键盘输入命令把文件的完整路径打进去再回车。这里有个细节:路径里如果有中文或者空格,某些系统环境下会出问题,稳妥的做法是把待上传文件放在纯英文短路径下,比如根目录建一个临时文件夹。
注意:文件对话框弹出后,脚本的后续命令是在系统层执行的,此时浏览器窗口必须保持在前台。如果中间有人切换了窗口,输入会打到别的程序里。跑这类任务的时候,最好让机器别被人动。
6.3 executeScript 与页面脚本隔离的误解
这个坑我踩过,而且踩了很久才想明白。工具里有两个名字很像的脚本执行命令,一个是沙箱版,一个是页面版,功能边界完全不同。
沙箱版跑在一个隔离的脚本环境里,能算数、能处理字符串、能读写变量,但拿不到页面上的任何元素。它适合做数据加工,比如把取到的文本去掉逗号再转成数字比较大小。
页面版才能真正操作页面文档对象,但它受页面自身的安全策略限制。如果页面设置了严格的内容安全策略,页面版命令可能直接无效或者报错,表现是"命令执行了但什么都没变"。
我的判断原则是:只做数据计算用沙箱版,要动页面元素用页面版,页面版失效就退回原生命令(点击、取值这些)来实现,别跟安全策略硬刚。顺便说一句,页面版返回的值类型也不一样,有时候拿到的是对象需要手动转字符串,这点在拼接 URL 或者写文件时特别容易出问题。
6.4 下载文件与落盘确认
下载这件事看着简单,实际是自动化里失败率最高的环节之一,因为它跨出了浏览器沙箱。
第一个前提是浏览器设置:默认下载目录要固定,并且关掉"每次询问保存位置"。这个开关不关,脚本点下载之后会弹出一个系统对话框,整个流程就卡死在那儿。
第二个是落盘确认。点击下载之后,文件不是立刻出现的,可能还在写盘。我一般的做法是循环检查目标文件是否存在、并且大小在若干秒内不再变化,才算下载完成。只看文件存在就往下走,后面读文件的内容时容易读到半截。
第三个是文件命名冲突。同名文件重复下载时,浏览器可能自动加序号后缀,这样你按固定名字去找就找不到。解决办法是每次下载前先清空下载目录,或者按时间戳生成预期文件名,再按这个预期名字去等。我倾向于清空目录,简单粗暴且可靠。
7. 完整案例:把每周报表导出压成一条命令
7.1 流程拆解与前置约定
讲个能直接照着做的例子。需求是每周一早上把某个后台的统计报表导出来,存到指定目录,文件名带上日期,导完之后核对条数。手动做大概需要三分钟,但必须准时,而且做的时候不能干别的。
拆解成动作序列是这样的:打开登录页、填账号密码、提交、等首页加载、进入报表菜单、设置日期区间、点查询、等表格出现、点导出、等文件落盘、重命名成带日期的名字、读取页面上的总条数写进日志、关闭浏览器。
前置约定有四条,必须在动手前定好:账号密码放在哪(我放在一个独立的本地配置文件里,脚本开头读取,不写在脚本里);日期区间怎么算(用脚本表达式算出上周一到上周日);下载目录是哪个(固定一个专用目录,每次跑之前清空);条数从页面哪个位置读(用一个稳定的元素定位,而不是截图识别)。
这四条约定清楚了,后面的实现才有依据。很多脚本写到一半写不下去,根本原因不是技术不行,是前置约定没定。
7.2 关键命令逐段说明
第一段是登录。账号密码从变量引用,不要硬编码。提交之后不要用固定等待,直接等首页上某个只有登录后才出现的元素,超时给足。
open | https://example.com/login | type | id=account | ${account} type | id=password | ${password} click | id=loginBtn | waitForElementPresent | css=.main-nav | 30000第二段是进报表页并设条件。日期用脚本表达式算,算完先写进日志,这样事后核对数据范围有据可查。设置完日期点查询,等表格首行出现。
store | 上周一 | dateFrom executeScript_Sandbox | var d=new Date(); d.setDate(d.getDate()-7); return d.toISOString().slice(0,10); | dateFrom type | id=startDate | ${dateFrom} click | id=queryBtn | waitForElementPresent | css=table.data tr:nth-child(1) | 30000第三段是导出与落盘确认。点导出之后,用循环检查文件是否出现并且大小稳定,稳定后才算完成。这一步我建议至少给 60 秒的容忍时间,报表大的时候写盘确实慢。
click | text=导出报表 | store | 0 | waitCount while | ${waitCount} < 30 | pause | 2000 | executeScript_Sandbox | return ${waitCount} + 1; | waitCount comment | 此处配合本地文件检查命令判断目标文件是否已稳定 | endWhile第四段是收尾。把文件重命名成带日期的格式,把总条数写进汇总日志,关闭窗口。重命名用本地文件操作命令,注意源路径和目标路径都要用绝对路径。
需要说明的是,上面的命令名以我手上这个版本为准,不同版本的下拉列表里叫法可能有细微差别。你在自己环境里做的时候,从命令列表里选对应的那一条就行,别死记名字,记的是"这一步要干什么、为什么这么干"。
7.3 结果校验与异常提醒
脚本跑完不等于任务成功,这一步很多人省略,然后就出现了"连续三周导出的是空报表但没人发现"的惨剧。校验我一般做三层。
第一层是文件层:文件存在、大小大于阈值、能被正常解析。空报表通常文件很小,一个大小下限就能挡住。
第二层是数据层:解析出来的行数大于零,关键列没有大面积空值。我会把行数和页面上显示的总条数做比对,两个数对不上就标记异常。
第三层是业务层:比如报表里有日期列,检查是不是都在预期区间内。这一层能挡住"参数设错导致导出了上上周数据"这类逻辑错误。
异常提醒不用搞得很复杂,往一个本地的日志文件追加一条带明显标记的记录就行,然后靠你自己扫一眼。想再进一步,可以让脚本在失败时把当时的页面截图保存下来,命名带上时间戳。截图是最有用的现场证据,比任何文字描述都直观。
最后再分享一个我在实际使用中形成的习惯:所有正式任务的脚本,我都会在文件头部写一段注释,记录这个脚本解决什么问题、依赖哪些外部文件、上次修改是因为什么。三个月后回来改的时候,这段注释能省下半小时的重新理解成本。工具本身不长腿,跑得稳不稳,全看这些不起眼的约定有没有落实。