4 界面图像自动化

在上一章中,我们讲述了“界面元素”,以及如何选取一个界面元素作为目标,以便使用“界面元素自动化”。当然,并非在所有的情况下,都能准确找到恰当的界面元素作为目标。因此,我们需要学会使用“界面图像自动化”,以备不时之需。

4.1 为什么不能使用界面元素?

在上一章中提到,我们在查找、操作界面元素的时候,实际上都是在调用界面元素所在的软件给我们提供的接口。UiBot所做的,实际上是把这些不同种类的接口统一起来,让编写流程的人不需要关注这些细节。但是,仍然会有一些软件,没有给我们提供查找、操作界面元素的接口;或者虽然提供了接口,但在最终发布时关闭了,这些软件包括:

  • 虚拟机和远程桌面

包含Citrix、VMWare、Hyper-V、VirtualBox、远程桌面(RDP)、各种安卓模拟器(如腾讯安卓模拟器)等。这些程序都由单独的操作系统在运行,和UiBot所在的操作系统是完全隔离的,UiBot自然无法操作另一个操作系统里面的界面元素。

当然,如果条件允许的话,可以把UiBot和流程涉及到的软件,都安装在虚拟机里,或者远程计算机里。这样一来,这些软件提供的接口就可以被UiBot直接使用了,因为它们还是运行在同一个操作系统里面的,本地计算机只是起到了一个显示器的作用而已。

  • 基于DirectUI的软件

以前,Windows软件界面的开发框架都是微软提供的,包括MFC、WTL、WinForm、WPF等。微软很贴心的为这些框架制作出来的界面都提供了自动化操作的接口。近年来,为了让软件界面更好看,也更容易制作,很多厂商或开发团队推出了自己的Windows软件界面开发框架。这类框架统称为DirectUI。用这些框架制作的界面,其界面元素都是“画”出来的,虽然人眼可以看到,但操作系统和其他程序都不知道界面元素到底在哪里。有的DirectUI框架提供了对外的接口,可以找到界面元素,有的则根本没有提供这样的接口,其它程序,包括UiBot,自然也无法找到界面元素。

实际上,UiBot Creator、UiBot Worker本身的界面就是用一种DirectUI框架开发的,这种框架称为Electron。Electron其实提供了界面元素的查找接口,但对外发布的版本默认都关闭了。所以,细心的读者可能会发现,UiBot里面的界面元素,反而是市面上任何RPA平台都无法找到的。

  • 游戏

由于游戏的界面强调美观和个性化,所以,一般游戏的界面元素都是“画”出来的,原理上和DirectUI类似。这种界面通常也没有提供接口,告知我们界面元素的位置。和基于DirectUI的软件不同的是,游戏界面变化速度快,对时效性的要求更高,一般来说,RPA平台并未针对游戏进行优化,所以在游戏上使用的效果不会太好。

如果要在游戏上使用自动操作,推荐使用按键精灵。按键精灵是专门为游戏设计的,内置了很多针对游戏的界面查找手段,比如单点颜色比对、多点颜色比对、图像查找等等。且运行效率更高。

4.2 无目标命令

我们在上一章中介绍了“有目标”的命令,相对的,UiBot也有“无目标”的命令。如下图所示,红框中表示有目标的命令,蓝框中表示无目标的命令。

有目标和无目标的命令
有目标和无目标的命令

如果遇到了没有界面元素作为目标的Windows软件,“有目标命令”自然就不能再用了,但仍然可以用“无目标命令”。 在图中这些无目标的命令里面,最重要的是“模拟移动”,因为“模拟移动”需要我们在命令中指定一个坐标点,在执行这条命令的时候,鼠标指针也会移动到这个坐标点;移动之后,我们再使用“模拟点击”命令,模拟按下左键,才能正确的按下某个按钮;或者正确的在某个输入框上设置焦点,之后,再使用“输入文本”命令,才能在焦点所在的输入框里面输入一段文本。

比如,有一个输入框,其中间的坐标是x:200, y:300。那么我们就需要先用“模拟移动”,并设定移动的坐标为x:200, y:300;再用“模拟点击”按下左键,设置焦点;再用“输入文本”,才能正常输入。否则,直接用“输入文本”的话,很大概率就输入到其他输入框里面了。

这里,我们有必要先解释一下Windows操作系统的屏幕坐标系。如果您之前了解Windows的屏幕坐标系,这一段可以跳过不看。

在Windows操作系统中,屏幕上的每一点都有一个唯一的坐标,坐标由两个整数组成,一个称为x,另一个称为y。例如坐标x:200, y:300的含义就是这个点的坐标的x值是200,y值是300。x是以屏幕左边为0开始计算,从左到右分别是0,1,2,3…,以此类推。y是以屏幕上边为0开始计算,从上到下分别是0,1,2,3…,以此类推。所以,坐标x:200, y:300所对应的点,其位置大致如下图中红圈所示:

Windows的屏幕坐标系
Windows的屏幕坐标系

只要有x和y两个整数值,就可以确定屏幕上一个点的位置。在UiBot中,有一些命令可以获得屏幕上某点的位置,并输出到一个变量里。如何用一个变量来保存x和y两个值呢?我们在后面学习UiBot所使用的BotScript语言的时候会了解到,BotScript中有“字典”数据类型,可以保存多个值。所以,UiBot在输出一个点的位置的时候,会输出到一个字典类型的变量中。假设这个变量名为pnt,则使用pnt["x"]pnt["y"]即可得到坐标的x和y两个值。

假如我们要找的界面元素在屏幕上的固定位置,那么用固定的坐标,配合无目标命令,即可正常模拟操作。但这种情况往往比较少见,因为Windows是多窗口系统,每个窗口的位置都可以被拖动,导致窗口里面的界面元素的位置也会发生变化。而且,在微信这样的软件中,联系人的位置也不是固定的,而是根据最近联系的时间排序的,位置随时可能发生变化。

所以,在UiBot中,一般不推荐直接写固定的坐标,因为变化的情况太多了,很难一一考虑周全。通常,如果使用无目标的命令,需要搭配其他命令使用,让其他命令能根据某种特征,找到界面元素的坐标,然后把找到的坐标当作变量,传给这些无目标命令。

在UiBot中,无目标命令的最佳拍档,是图像命令。两者结合使用,才能实现“界面图像自动化”。

4.3 图像命令

除了常用的“鼠标”、“键盘”类之外,UiBot的“图像”类命令也是很强大的。在UiBot Creator的命令区,找到“图像”,单击展开,可以看到其中包含了如下图所示的几个命令:

UiBot Creator里面列出的“图像”类命令
UiBot Creator里面列出的“图像”类命令

我们首先来看“查找图像”这条命令,其作用是:首先指定一个图像文件,格式可以是bmp、png、jpg等(推荐使用png格式,因为它是无损压缩的),然后在屏幕上的指定区域,按照从左到右,从上到下的顺序依次扫描,看这个图像是否出现在指定区域当中。如果出现,则把其坐标值保存在一个变量中,否则发生异常。

看起来好像很复杂,又要指定图像文件,又要指定扫描的区域。实际上,使用UiBot Creator的话,操作非常简单。

比如,著名的游戏平台Steam,其界面就采用了DirectUI技术。我们以其登录对话框为例(如下图),其中的账户输入框、密码输入框、登录按钮等元素都无法被任何RPA工具直接获取到。这时候就需要用到图像命令。

Steam的登录对话框
Steam的登录对话框

假设已经启动了Steam,并打开了其登录界面,且Steam已经自动保存了有效的用户名和密码,只差点击“登录”按钮了。下面,在UiBot Creator中编辑一个流程块,并以双击或拖动的方式,插入一条“查找图像”命令,点击命令上的“未指定”按钮并在弹出菜单中选择“从界面上选取”:

使用“查找图像”命令
使用“查找图像”命令

和有目标命令类似,UiBot Creator也会暂时隐藏,图标会变成一个箭头和一张图片的样子。此时,按下左键,并向右下方拖动,直到画出一个蓝框,且蓝框中已经包含了要找的图像,松开鼠标左键,大功告成!

“查找图像”命令指定图像和查找范围
“查找图像”命令指定图像和查找范围

看起来,上面的操作只是画了一个蓝框,但是,UiBot Creator已经帮我们做了两件事情:

  1. 判断蓝框落在哪个窗口上,并记录这个窗口的特征,将来找图的时候,也需要先找到这个窗口,并在这个窗口的范围内找图。

  2. 对蓝框所框住的部分截图,自动保存为一个png格式的文件,并自动把这个文件保存在当前所编写的流程所在目录的res子目录中。这就是将来要查找的图片。

用鼠标单击这条“查找图像”命令,将其置为高亮状态,右边的属性栏会显示出这条命令的属性,如下图所示:

“查找图像”命令的属性
“查找图像”命令的属性

其中,画红框的两条属性,也是最重要的两条属性,就是前面所说的,UiBot Creator帮我们做的两件事情。其他各个属性里面,“相似度”是一个0-1之间的数字,可以包含小数位,这个数字越接近1,UiBot在查找图像时,越严格要求每个点都必须匹配上,通常取0.9,表示允许出现一小部分不匹配的情况,只要大体匹配即可。“光标位置”属性的含义是,当找到图像时,由于图像是一个矩形,而命令输出只是一个点的坐标,究竟要返回矩形中的哪个点的坐标,通常取“中心”即可。“激活窗口”属性表示在找图之前,是否需要先把所查找的窗口放到前台显示。如果窗口被遮住了,即使窗口上有我们要找的图像,也无法正确找到,所以这个属性通常也设为“是”。

其他的属性通常不用改,保持默认值就好。在“输出到”属性中,已经指定了一个变量名objPoint,如果成功的找到了图像,会把结果保存在这个变量中。我们来看看这个变量中保存了什么内容:在命令区的“基本命令”类中找到“输出调试信息”,将其插入到查找图像命令的后面,并且在属性中指定输出内容为objPoint(注意,此时应将属性左边的标有"Exp"的按钮切换为蓝色,表示这是可以输入变量和表达式的“专业模式”,然后输入变量名objPoint,或者按"fx"按钮直接选择变量)。如图所示:

用“输出调试信息”查看结果
用“输出调试信息”查看结果

假设要查找的图像确实能在屏幕上看到,运行这个流程块后,得到结果:

{ "x" : 116, "y" : 235 }

具体的数值在不同的计算机上可能有所不同,但原理不变。这个值是一个“字典”数据类型,当这个值保存在变量objPoint中的时候,只需要写 objPoint["x"]objPoint["y"] 即可得到其中的x和y值。

下面,得到了图像的中心位置,只需要用鼠标去点击这个位置,即可模拟Steam的登录操作了。选用“鼠标”类中包含的“模拟移动”和“模拟点击”命令,即可很好的完成任务。

如下图,“模拟移动”命令最关键的属性,就是要操作的屏幕位置。将“横坐标”和“纵坐标”两个属性分别切换到“专业模式”,并依次输入查找图像的结果 objPoint["x"]objPoint["y"] 即可。移动完成后,再来一个“模拟点击”,让左键在登录按钮的中心点下去。至此,我们已经模拟出点击“登录”按钮的全套操作。

一套完整的“查找图像并点击”操作
一套完整的“查找图像并点击”操作

上面三条命令很容易看懂,即使是从来没有学过UiBot的用户,也能大致了解其含义。但是,仅仅为了点一个登录按钮,还需要三条命令才能完成,显然过于复杂了。这时候,请再回头看一下UiBot提供的“图像”类下的所有命令,其中第一条命令叫“点击图像”,它其实就是“查找图像”、“模拟移动”、“模拟点击”三条命令的组合,只要插入一条“点击图像”命令,并按下命令上面的“从界面上选取”按钮,拖动鼠标选择要查找的窗口和要查找的图像,即可快速完成模拟点击Steam的“登录”按钮的功能。虽然是无目标的命令,但其操作便捷程度并不逊于有目标的命令。

有了上述基础,对于其他几条图像类的命令,包括“鼠标移动到图像上”、“判断图像是否存在”等等,您应该可以举一反三了,本文不再赘述。

4.4 实用技巧

在上一章中,我们学习了界面元素自动化,而在这一章中学习了界面图像自动化。我们看到,在大多数情况下,并不能单纯的使用“无目标命令”,而是要结合图像类命令,动态的在屏幕上找到要操作的位置,所以才称之为“界面图像自动化”。

那么,在具体完成一个流程任务的时候,该优先选择界面元素自动化,还是优先界面图像自动化呢?我们给出的答案是:优选界面元素自动化!只要能获得恰当的界面元素作为目标,就应该优先考虑使用界面元素。因为使用界面图像自动化,有以下的缺点:

  • 速度通常会慢于界面元素自动化;
  • 可能受到遮挡的影响,当图像被遮挡时,即使只遮挡了一部分,也可能受到很大影响;
  • 往往需要依赖图像文件,一旦丢失图像文件就不能正常运行;
  • 某些特殊的图像类命令必须连接互联网才能运行。

当然,这些缺点也是可以部分缓解的,以下技巧能帮您更好的使用图像类命令:

首先,请牢记一个“小”字。在截图时,尽量截取较小的图像,只要能表达出所操作的界面元素的基本特征即可。在指定查找的区域时,尽量缩小区域。这样不仅速度会有所改善,而且也不容易受到遮挡的影响。比如下图中的“登录”按钮,没必要像左图一样,把整个按钮作为一幅图像来查找,只要像右图一样选择最关键的部分就可以了。

选择较小的截图
选择较小的截图

其次,大部分图像命令都支持“相似度”的属性,这个属性的初始值是0.9,如果设置过低,可能造成“错选”,如果设置过高,可能造成“漏选”(“错选”和“漏选”的概念请参考上一章)。可以根据实际情况进行调整,并测试其效果,选择最佳的相似度。

再次,屏幕的分辨率和屏幕的缩放比例对图像命令可能有非常关键的影响。因为在不同的分辨率下,软件的界面显示可能完全不一样,导致图像命令失效。所以,请尽量保持运行流程的计算机和开发流程的计算机的分辨率、缩放比例都是一致的。在Windows 10操作系统上设置分辨率和缩放比例的界面如下图所示:

设置分辨率和缩放比例
设置分辨率和缩放比例

最后,对于图像命令来说,经常需要和图像文件打交道。当需要使用图像文件时,我们固然可以用一个绝对路径来测试,如D:\1.png。但是,这就要求在运行此流程的计算机上,也必须在同一路径下有同样的文件,否则就会出错。有一个改进的方法,就是在您的流程所在的文件夹中,可以看到一个名为res的文件夹,把图像或其他文件放在这个文件夹中,并在流程中使用表达式@res"1.png"来代表这个文件即可。这样的话,当前流程发布到UiBot Worker使用的时候,也会自动带上这个文件。并且无论UiBot Worker把这个流程放在哪个路径下,都会自动修改@res前缀所代表的路径,使其始终有效。

另外需要说明的是,本章所描述的图像类命令使用技巧,绝大部分也适用于OCR命令,关于OCR命令的概念和使用方法,因篇幅所限,本章不再赘述。

4.5 智能识别

如前所述,虚拟机、远程桌面、基于DirectUI的软件、游戏等应用程序,无法直接使用有目标命令的“从界面上选取”功能定位界面元素。在这种情况下,只能使用无目标命令和图像命令配合的方式,但图像命令有一些使用技巧不易掌握,在掌握不好的情况下,非常容易出现“错选”或者“漏选”。因此,UiBot Creator从5.0版本开始,支持智能识别功能,这是另一种基于图像进行界面元素定位的方法。我们先从一个具体实例来看看智能识别的用法。

打开Windows自带的画图程序,绘制一个矩形框,假设此时的需求是:通过UiBot找到并点击这个矩形框。

一个按钮的界面
一个按钮的界面

如前所述,有目标命令是无法找到这个矩形框的,我们来看看如何通过智能识别命令找到并点击这个矩形框。在UiBot Creator的命令区,找到“界面操作”,单击展开,找到“智能识别”,再单击展开,可以看到其中包含了如下图所示的一组命令:

智能识别命令列表
智能识别命令列表

首先插入一条“智能识别屏幕范围”命令,然后点击这条命令上的“查找目标”按钮,UiBot的界面暂时隐藏起来了,出现了一个红边蓝底的半透明遮罩,鼠标移动到什么地方,这个目标选择器就出现在什么地方。细心的同学已经发现这个功能跟有目标命令的“从界面上选取”按钮的功能是一样的!

智能识别屏幕范围
智能识别屏幕范围

选取完屏幕后,再插入一条“智能识别后点击”命令,然后点击这条命令上的“查找目标”按钮,这里的“查找目标”按钮的用法仍然与有目标命令的“从界面上选取”按钮相同。这个时候神奇的现象出现了:UiBot居然将刚才我们绘制的一个矩形框认出来了!

智能识别后可以找到矩形框
智能识别后可以找到矩形框

也就是说,通过“智能识别屏幕范围”命令,UiBot将原来无法识别的界面,通过人工智能图像识别,将界面中一个个潜在的元素给提取出来,并供后续的命令使用,这些后续命令包括“智能识别后点击”、“智能识别后获取文本”、“智能识别后输入文本”、“智能识别后鼠标悬停”、“智能识别后判断元素是否存在”等命令。从这个角度也可以理解,“智能识别后点击”等命令,必须在“智能识别屏幕范围”命令之后执行,且必须在“智能识别屏幕范围”命令的范围内才有效(在“智能识别屏幕范围”命令缩进范围内)。

智能识别多条命令组合使用
智能识别多条命令组合使用

运行该流程,可以看到成功地点击了该矩形框。

如果用户界面中存在两个或两个以上外观相同的界面元素,UiBot如何定位我们想要找的那个界面元素呢?我们还是通过具体实例来讲解:打开画图程序,把刚才绘制的矩形框再复制一份,这样画图界面中就同时存在两个一模一样的矩形框了,假设现在的需求是:通过UiBot找到并点击右边那个矩形框。

两个按钮的界面
两个按钮的界面

这时,需要重新点击“智能识别屏幕范围”命令的“查找目标”按钮,因为需要识别的屏幕内容已经发生变化,需要对屏幕重新进行智能识别。从这个角度来看,“智能识别屏幕范围”命令其实是一个预先执行的静态命令,而不是流程运行过程中动态进行查找目标。所以一旦屏幕图像有变化,都需要对屏幕图像重新进行智能识别。

然后,再点击“智能识别后点击”命令的“查找目标”按钮。这个时候我们可以发现,两个矩形框都处于可以选择的状态。我们选择右边那个矩形框,此时右边矩形框被遮罩框遮住,同时有一条虚线,将右边矩形框与一个“形状”字样连接起来,如下图所示:

在两个相同矩形框中定位某个矩形框
在两个相同矩形框中定位某个矩形框

原来,UiBot使用了一种叫做“锚点”的技术,来定位两个或多个外观相同元素的位置。所谓“锚点”,指的是屏幕中某个独一无二的元素(比如上述“形状”字样),利用不同矩形框相对于该锚点的位置偏移和方位角的不同,即可唯一地定位矩形框。

运行该流程,可以看到成功地点击了右边的矩形框。