跳到主要内容

从一个 Windows 程序抄进另一个

每间办公室里最古老、最没被自动化的活:清单在一个程序里,表单在另一个程序里,然后有人坐着重新敲一遍。两边都没有对方能导入的导出功能,所以它们之间唯一的通道,就是人用的那条——屏幕、键盘和剪贴板。

本页把这个流程从头到尾搭出来。这是一个真实流程,30 个节点,能跑到 Success。

目标

从一个文本文件里读出五条客户记录,逐条录入运行在 Chrome 里的一个网页表单,而进入表单这一步前面还挡着验证码。

它演示了:

  • 同时握住两个窗口,每个都按别名称呼,而不是"眼下在最前面的那个"
  • 一次 Ctrl+C 就把整个文件取回成一个流程变量
  • split() 把那一个字符串切成五条记录、每条五个字段
  • 验证码外面套一层有界重试——三次为止,绝不无限循环
  • 点在 Find Image 刚找到的地方,而不是一个固定坐标

前提: 已打开桌面模式,且流程的目标是桌面。

它长什么样

三个变量,都是流程作用域:

变量类型默认存什么
vars.noidungstring""整个数据文件,就是复制下来的样子
vars.inumber0循环走到第几条记录
vars.jnumber0验证码试到第几次

第 1 步 — 打开两个程序,并给它们起名

两个 Open App 节点。要紧的不是它们能启动什么,而是每一个都以一个名字占住一个窗口,供流程其余部分使用

表单数据文件
程序chrome.exenotepad.exe
参数--app=http://…/form.html--window-size=1000,760--window-position=880,60、一个私有的 --user-data-dir…\khach_hang.txt
Execution ContextSpecific WindowSpecific Window
标题包含QLBHkhach_hang
别名qlbhnguon
Wait after1200 ms1200 ms

请用 Browse… 去挑程序,而不是手敲路径。它接受 .exe、接受 .bat,而且——很实用——接受 .lnk,所以桌面上现成的浏览器快捷方式就是个合法答案。

给 Chrome 一个自己的 profile

--user-data-dir 指向一个私有位置,才是这件事可重复的原因。没有它,Chrome 会把 URL 交给你已经开着的那个窗口,于是流程连你的标签页、你的登录会话、你的通知弹窗一起继承过来。有了它,流程每次都拿到一个干净窗口,而你自己的浏览毫发无损。

别名是整个设计的要点。 后面每个节点都在自己的 Execution Context 里点名 qlbhnguon,所以无论流程运行期间用户点了什么,"敲这个"和"复制那个"都落在正确的程序里。这个流程里没有任何一个节点作用于"当前活动窗口"。

第 2 步 — 过验证码,而且要有界

一个 solveAndApply 模式的 Captcha 节点,范围限定在 qlbh 窗口的一块区域上,过掉第一道门。第二道门——验证码——被包在一个不会永远跑下去的循环里:

Loop "ma",Count 模式,最多 3 次,计数器 vars.j
Captcha:读出码并敲进去 (超时 60s / 20s)
Find Image:商品列表出来了吗?
Success → Break
Failure → Loop End(再试)
Loop End

真正做验证的是 Find Image。验证码节点成功只意味着它敲了点什么,不代表站点接受了——所以流程去找一个只存在于门后面的东西,找到了才跳出循环。

三次为止,然后循环自己结束。没有上界的重试,是无人值守的流程变成卡死进程的头号方式。

第 3 步 — 一次复制,把整个文件取回来

这是值得偷师的一招。三个节点,全都 scope 在 nguon 上:

节点设置为什么
Click覆盖文本区的一块区域,waitAfterMs 400取焦点。窗口在最前面不等于它的文本框正在收键
Key PressCtrl + A全选
Key PressCtrl + C复制到变量 noidung,超时 3000 ms复制到的文字落进一个流程变量

复制到变量这一栏把一次复制组合键变成一次读取。这个节点之后,vars.noidung 精确地持有文件内容——带重音也不丢——而且全程没有 OCR 参与,所以没有什么可读错的。

复制前的那次点击不是可选项

如果复制没有发生,节点走 Failure,而不会把剪贴板上原有的旧值返回。这是有意的:两者从内容上无法区分,而一个悄悄把上周的复制内容敲进表单的流程,错得没人会察觉。最常见的原因是焦点——所以才有那次 Click。

第 4 步 — 用 split() 走过每条记录

数据文件一行一个字段,每条记录五个字段:

KH001
Nguyễn Văn A
0901234567
12 Lê Lợi, Q1
1500000
KH002

一个循环走五条记录,每个字段就是切片里的一个下标:

Loop "don",Count 模式,最多 5 次,计数器 vars.i

Input Text split(vars.noidung, "\n")[vars.i * 5 + 0] → 客户编号
Key Press Tab
Input Text split(vars.noidung, "\n")[vars.i * 5 + 1] → 客户姓名
Key Press Tab
Input Text split(vars.noidung, "\n")[vars.i * 5 + 2] → 电话
Key Press Tab
Input Text split(vars.noidung, "\n")[vars.i * 5 + 3] → 地址
Key Press Tab
Input Text split(vars.noidung, "\n")[vars.i * 5 + 4] → 金额
Key Press Tab
Key Press Enter → 保存

Loop End

vars.i * 5 + n 就是全部的下标方案:循环计数器挑记录,常数挑字段。文件改成每条六个字段,也只是一个数字在五个地方变一下。

字段之间用 Tab 移动,因为人就是这么做的——它不需要任何坐标,而且窗口被挪动或改大小它照样活着。

第 5 步 — 点在刚找到图像的位置

在循环内部、敲字之前,一个 Find Imageqlbh 上定位商品行,紧随其后的 Click 并不使用固定坐标。它的目标是一个实时的 Find Image 结果——那次查找刚刚产出的坐标。

这很重要,因为列表会滚动。固定坐标在页面挪动之前都是对的;而来自刚跑过的那次查找的坐标每次都对,并且一旦查找失败,这一点击根本不会发生。

结果

流程终止于一个状态为 successStop 节点,Desktop Dashboard 上它带着绿色的 Success 出现在队列里。

运行之后的 Desktop Dashboard

一台机器,一次一个流程,以及队列里一次已完成的运行。

为什么这样搭

决定另一种做法,以及为什么不
窗口按别名握住"活动窗口"——用户手一滑,流程就把字敲进了他们的邮件
剪贴板,不用 OCROCR 会读错;复制不会。没有文字可复制时才用 OCR,而不是有的时候
一次复制,然后 split()五十对 Shift+End/Ctrl+C——五十次丢焦点的机会
验证码循环限 3 次无界重试正是流程变成挂死进程的方式
Find Image 负责验证,验证码只负责动作验证码节点敲进去了,不等于站点收下了
Find Image 结果取点固定坐标在列表滚动之前都是对的
字段间用 Tab五个坐标,窗口一改大小就全废

提示

  • 先 Test Node,再 Test Flow。 每个节点都能单独检查,而且检查时它会绑定自己的 Execution Context——所以你不必坐等验证码走完,就能确认那次 Ctrl+C 真的把 noidung 填上了。
  • 留意那些 waitAfterMs 它们很小(105–700 ms),而且是承重的:一个在 Tab 之后重绘的表单,对这段停顿的需要超过对敲键速度的需要。
  • 给循环一个你说得清的上界。 这里的 最多 5 就是记录条数;如果文件可能更长,请把条数读出来,而不是往高了猜。
  • 把数据文件的形状放在一个地方。 那个 * 5 出现在五个表达式里。如果它还会再长,一个存着字段数的 Variable 节点值这一个节点。

注意与限制

  • 一个桌面,一次一个流程。 桌面运行是顺序的——这个工作区没有实例集群,所以第二个流程要排队。
  • 剪贴板是整机共用的。 另一个流程在同一刻复制,与这个流程无法区分。同时只应有一次复制在途。
  • Chrome 的 --app= 窗口未必能被唯一描述。 它会生出一个不可见的孪生窗口,标题窗口类都一样。如果窗口选择器拒绝选定,请改用一个普通 Chrome 窗口——那个是能描述的。
  • split() 不会自动 trim。 数据文件末尾多一个空行,就会变成一条空记录。请先对复制内容 trim(),或者确保文件结尾没有换行。

相关页面