一、简介
1.什么是RPA?
Robotic Process Automation,中文翻译为机器人流程自动化,简称RPA。
RPA是软件机器人,用来完成计算机上重复的工作。
2.UiBot是什么?
UiBot是一种RPA平台
3.RPA平台组成部分
1.开发工具:制作、运行、调试软件机器人
2.运行工具:普通用于运行已有流程,查阅结果。
3.控制中心:对多台PC上的机器人集中控制(分发流程、设定启动条件等)
Creator把流程先上传到Commander,再由Commander统一下发给各个Worker,并统一指挥各个Worker执行流程
UiBot的三个组成部分
二、基本概念
流程 > 流程快 > 命令 > 属性
1.流程:UiBot流程是一连串的执行动作,以流程图的方式显示,包含一个文件夹。
2.流程图:
包含“开始”、“结束”、“流程块”和“判断”四种元素,用箭头连起来。
只能有一个“开始”元素,可以有多个“结束”元素,可以有多个“判断”元素,至少一个“流程块”。
一个流程分多个步骤,每个步骤用流程块来描述(冰箱打开 -> 装进大象 -> 关上冰箱)。
推荐把逻辑独立的封装成一个流程块,留个流程块最好不要超过20个,多个沟通起来困难。
3.可视化视图
命令:把一个步骤具体细化成命令去执行,如:模拟鼠标、键盘操作,对窗口、浏览器操作等
属性:细化描述具体的命令
4.源代码视图
5.小结
这一章学习了四个概念:流程、流程块、命令、属性。还看到了三种视图:流程图、可视化视图、源代码视图。它们之间的关系如下图所示:
流程包含多个流程块,流程块包含多个命令,命令包含多个属性。流程图是流程的展现,可视化视图和源代码视图都是流程块的展现。
6.进阶:流程图的输入和输出
流程图中的变量,其作用域也仅限于当前流程中,在流程块里面是无法直接使用的。
当一个流程块开始运行的时候,可以把一个值(可以是变量或者表达式)“输入”到流程块中;而当一个流程块运行结束的时候,也可以把一个值“输出”到流程图中的某个变量中。还可以在流程图中加入一个“判断”,根据某个值,来决定究竟后面要找哪条路径去运行。
UiBot用到的编程语言是不区分关键字、变量名的大小写的,所以您也可以写 SELF.INPUT
、self.input
,或者 RETURN <输出值>
等。
流程图的属性栏
如下图所示,“判断”元素有两个出箭头,一个标有yes,一个标有no,当其属性中的“条件表达式”为真时,沿着yes箭头往后运行,否则,沿着no箭头往后运行。
流程图输入和输出的具体用法:
我们首先选中“流程块1”,在其“输出”属性中,填写一个变量名,假设是X
;然后选中“流程块2”,在其“输入”属性中,填写同样的变量名(不区分大小写)。这样,通过变量X
,就把“流程块1”的输出和“流程块2”的输入连接起来了。如下图所示。 这个变量X
仅在当前流程图中有效,其作用仅仅是把两个流程块连接起来。在流程块1和流程块2中,均无法直接使用X
来设置或者获取其值。
通过同一个变量,连接流程块1的输出和流程块2的输入
如何让流程块1输出,又如何让流程块2输入呢?
我们先点击“纸和笔”图标进入流程块1,只需要插入一条“获取系统时间”和一条“格式化时间”命令(在“时间”分类下),并把“格式化时间”中的“时间”属性设为“获取系统时间”的结果,即可得到当前时间,并以容易阅读的格式保存在变量sRet中。 然后,再插入一条“跳出返回”命令(在“词法语法”分类下),并把sRet设为返回值,即可让流程块1正确输出。如下图所示。为了方便读者理解,图中同时列出了这个流程块的可视化视图和源代码视图,读者可根据掌握程度任选其一。
在流程块1中输出当前时间
再点击“纸和笔”图标进入流程块2,只需要插入一条“输出调试信息”命令,并把“输出内容”属性设为Self.Input(不区分大小写)即可。如下图所示。同样,我们也列出了这个流程块的可视化视图和源代码视图,以方便理解。
在流程块2中输出调试信息,信息来自于流程块1
回到流程图界面,然后点击“运行”按钮,即可看到运行结果。注意,由于流程块2需要获得流程块1的输出,所以,在流程图中运行的结果是正确的。虽然流程块2也可以单独运行,但在单独运行时,由于缺乏流程块1的输出,结果可能会有不同。
三、界面元素
1.什么是界面元素?
鼠标下面都是一个小的图形部件,我们把这些图形部件称为“界面元素”。
在UiBot中,界面元素的作用,就是作为“有目标”的命令中的目标使用。
2.目标选取
“点击目标”命令和“选择目标”按钮
用“目标选择器”选中开始菜单按钮
“目标”属性的值
{"wnd":[{"app":"explorer","cls":"Shell_TrayWnd"},{"cls":"Start","title":"开始"}]}
3.目标编辑
目标常见错误:
- 无论如何移动鼠标,都无法使遮罩恰好遮住要作为目标的界面元素(通常是遮罩太大,遮住了整个窗口)
- 遮罩可以恰好遮住界面元素,但用生成的数据查找目标时,发生了:
- 错选:找到界面元素不是我们选的
- 漏选:界面元素存在,却找不到
修改目标
目标编辑器
0:这是目标的上级界面元素 1:是目标界面元素,程序逐级从上往下查找。
- 不理解的特征名称,比如
cls、aaname
等,暂时不管它们; - 善用通配符
*
,代表“匹配任意内容”。如界面元素title
特征的值是“姓名:张三”,“张三”可能变,但“姓名:”不变。所以,可以用title: "姓名:*"
来作为特征,而不是把这条特征去掉; - 去掉特征的时候要慎重。去掉特征可以减少漏选,但会增加错选。流程运行时漏选易发现,错选不易发现。
大多数的“有目标”命令在找不到目标时会报错,除非:(1)判断了目标是否存在 (2)用Try…Catch捕获异常。
程序错选的时候,UiBot并不知道,还会继续往下运行。
提醒:不同操作系统、浏览器上,同样的界面元素特征可能不一样。
所以,在用UiBot制作流程,并且在别人的计算机上使用的时候,请尽量保持开发环境和生产环境的一致性,以减少不必要的错误。
4.进阶
遮罩选取目标常见问题:只能遮罩选取整个窗口,不能具体选中目标界面元素。
如何正常选取?
1.Chrome浏览器:
Chrome浏览器需要安装扩展程序“UiBot Native Message Plugin”,并启用。
推荐大家在RPA流程中还是使用原生的Chrome浏览器或IE浏览器(360安全浏览器、QQ浏览器等容易出错)
2.跨域网页
网页中通过iframe嵌套了另一个域名下的网页(不同的二级域名或顶级域名),Chrome浏览器处于安全考虑,禁止对引用的网页访问,如元素选取,执行JS等,无法自动化操作。(IE可以)
解决办法:
(1)使用IE浏览器
(2)通过启动参数命令,来关闭Chrome的安全设置
右键点击Google Chrome图标,选择 属性->快捷方式,在“目标”一栏填入启动参数,具体格式如下:<Chrome安装路径> --disable-web-security --user-data-dir=用户数据目录
。比如,我们的Chrome安装在C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
下,用户数据目录为D:\temp
,那么套用格式,我们在Chrome目标窗口应填入C:\Program Files (x86)\Google\Chrome\Application\chrome.exe --disable-web-security --user-data-dir=D:\temp
,如下图:
Chrome关闭安全设置
在目标后添加(双引号后面): --disable-web-security --user-data-dir=D:\temp
在经过以上操作后,我们再打开Chrome,会看到Chrome地址栏会有如下的提示,并且安装的扩展程序也消失不见了。不要着急,这是因为Chrome的用户数据目录发生了变化,只要重新安装UiBot的Chrome扩展程序,即可自动化操作。
Chrome关闭安全设置后打开显示
经过以上设置,Chrome即可支持跨域访问。
3.SAP客户端程序
SAP客户端程序需要在设置中打开脚本支持,才能正常选取。我们以SAP 710客户端为例:
- 打开SAP客户端程序,进入登录主界面;
- 输入rz11事务码并进入相应界面;
SAP输入事务码
- 在事务界面输入sapgui/user_scripting,并点击display;
rz11事务界面
- 查看Current Value当前值选项,如果为TRUE则已经开打选项,不需要做任何改动;如果为FALSE则需要点击Change Value改变此处为TRUE;
sapgui设置界面
- 点击设置按钮,选择Options项;
SAP客户端设置选项
- 切换到Scripting选项卡,勾选“Enable Scripting”选项,并取消勾选“Notify When a Script Attaches to Running Man GUI”和“Notify When a Script Opens a Connection”选项。
SAP客户端Scripting选项卡设置
设置完成后,即可象普通的Windows软件一样,用UiBot对SAP客户端进行界面元素的获取和操作。除了前文中介绍的“鼠标点击”、“键盘输入”等操作之外,我们来看一个新的例子,用UiBot自动设置单选框的内容:
在“界面元素”类的命令下,找到“设置元素勾选”命令,拖动插入到组装区。按下“查找目标”,可以看到UiBot的界面元素选择遮罩可以准确的遮住SAP客户端中每个单选框的位置。选中我们关注的单选框,并在命令属性栏的“是否勾选”选择“是”即可。如图所示:
SAP客户端Scripting选项卡设置
运行此流程,即可看到SAP客户端的单选框被UiBot自动设置为“Display inbound call”一项。
4.JAVA程序
UiBot支持Swing、AWT、JNPL、Applet等多种Java应用程序。除Swing以外,其他Java程序都需要安装Java扩展程序。
可以按照如下步骤去安装Java扩展程序:
-
打开UiBot Creator,随便选择一个流程。在菜单中选择“帮助”->“安装Java扩展”;
-
安装成功之后,UiBot Creator将会有对应的安装成功提示出现。需要注意的是,如果需要操作的Java程序是以管理员权限进行安装,那么同样需要以管理员权限启动UiBot Creator,才能顺利安装Java扩展程序。
安装后,即可象普通的Windows软件一样,用UiBot对Java程序进行界面元素的获取和操作。
5.进阶:网页目标
网页目标:百度主页的二维码
wnd
信息标明了这个网页所在的浏览器窗口,html
信息才是网页上的界面元素的关键信息。
html
:代表这是一个网页界面元素;
url
:对应浏览器地址栏中显示的URL,不参与元素特征匹配。仅在“绑定外部浏览器”命令中(在“浏览器”类命令中可以找到)用到,用于选择想要绑定的浏览器活动标签页;title
:与url类似,对应浏览器标签页的标题,不参与元素特征匹配,也仅在“绑定外部浏览器”命令中使用;tagName
:html标签类型(div、a、input
等);
attrMap
:对界面元素详细的html描述;
index
:一般起辅助作用,说明在满足特征条件情况下,元素出现的顺序。UiBot的index是从数字1开始的,当index没有填写或取0时,则会选择第一个出现的元素。
实例:获取产品月销量
具体步骤:
- 从UiBot Creator的命令区选择“获取元素文本”命令,如下图:
获取元素文本命令
- 在“获取元素文本”命令上点击“查找目标”按钮,并选择销量数字,如Intel i5 8500页面的“98”,如下图:
选中需要获取的文本
- 用“输出调试信息”命令查看抓取到的值(当然,也可以用于其他用途,如转换成数字、保存到Excel表格等,本文暂不赘述其他用途),如下图:
查看抓取的内容
看起来,好像工作得很好,毫无问题的获得了Intel i5 8500的月销量:98。但是,如果我们在其他商品上再去运行这个流程(使用Chrome浏览器,只需切换页面的标签即可,UiBot始终会在激活的标签工作),就会发现出问题了。
在其他商品上运行流程
可以看到,在等待一定时间之后,UiBot最终因为没有找到目标而抛出了异常。那么,问题到底出在什么地方?我们应该如何做,才能让UiBot顺利找到目标呢?
点击“获取元素文本”命令,查看命令的属性,并具体打开“目标”属性进行查看,如下图:
细心的读者可能已经发现了:原来"aaname"
这条特征已经被固定在“98”了。这显然是不合理的:我们本来就是为了获取销量,如果把销量的数值98也加到特征里面,那是毫无意义的!因为销量一旦发生变化,特征就无法匹配了,造成“漏选”的问题。怎么办呢?我们可以很自然的想到:取消aaname
特征的勾选状态,或把aaname
的特征采用"*"
进行通配,即可跳过这条造成“漏选”的特征。如下图:
修改“aaname”的特征为通配符
请注意,这里不必纠结上面图片框里显示的98,那只是一张参考图,在实际查找目标的时候不会起到任何作用。也不必纠结title
和url
这两条特征,因为前文已经提到,这两条特征也不会参与到查找目标的过程中。
修改完成之后,再次运行这个流程块,看看是否能正确获取其他商品的月销量。如下图:
修改“aaname”特征之后的运行
奇怪的事情发生了,之前的异常确实没有出现,并且获取到了内容。但是并不是我们想要的“77”,而是“月销量”几个字,这是怎么回事呢?
我们观察一下页面上的内容,发现修改“aaname”之后,虽然不会发生“漏选”,但由于文字“月销量”的特征和“77”完全一致,造成了“错选”。仔细查看即可发现,“月销量”文字和“77”的tagName、attrMap
等特征完全一样,好比是一个户口本里的同一家人,已经无法区分了。怎么办呢?可以使用"index"
特征来定位他们的不同。上文提到,UiBot的index
是从数字1开始的,当index没有填写或取0时,则匹配第一个。从页面上看,“月销量”这个元素在销量数字的前面,如果它是第一个,那么销量数字就应该是第二个,因此,我们猜测,当的index
取2的时候,就可以找到销量数字了。不妨填上试一下。
修改“index”特征的值
现在验证一下。在UiBot Creator工具栏上,点击“运行”按钮,直接运行当前的流程块。可以看到,在其他商品的页面上,也可以正确的拿到了其月销量数据了。
实际操作中,多多尝试和总结经验。
四、无目标命令
1.为什么没有目标?
UiBot所在的系统和目标不在统一系统中,无法操作目标界面元素。
虚拟机和远程桌面,如:Citrix、VMWare、Hyper-V、VirtualBox、远程桌面(RDP)、各种安卓模拟器(如靠谱助手)等
解决办法:可以把UiBot和流程涉及到的软件,都安装在虚拟机里,或者远程计算机里。
基于DirectUI的软件:元素是被画出来的,UiBot无法找到。
游戏:元素是画出来的,界面变化快,时效性要求高,RPA对游戏效果不好。游戏推荐按键精灵。
2.无目标命令
有目标和无目标的命令
最重要的是“模拟移动”:设置坐标位置 - 模拟移动 - 模拟点击 - 输入文本
Windows坐标理解为第4象限,坐标x:200, y:300,x轴是距离屏幕左边的水平方向的距离,y轴是距离屏幕上面的垂直方向的距离。
Windows的屏幕坐标系
坐标保存在BotScript语言的字典中,字典可以存放多个值,变量名为pnt
,则使用pnt["x"]
和pnt["y"]
即可得到坐标的x和y两个值。
固定坐标情况很少,一般都会有变化的,一般推荐使用其他命令根据某种特征,先找到界面元素的坐标,然后把坐标当做变量穿给无目标命令。
在UiBot中,无目标命令的最佳拍档,是图像命令。
3.图像命令
UiBot Creator里面列出的“图像”类命令
“查找图像”命令:指定一个图像文件,格式png(无损压缩,推荐)、bmp、jpg等,扫描查找是否在指定区域,没有则发生异常。
使用“查找图像”命令并指定图像和查找范围
“查找图像”命令的属性
“激活窗口”:把窗口放到最前面显示,防止被其他窗口遮挡,一般都默认是。
用“输出调试信息”查看结果
结果:
{ "x" : 116, "y" : 235 }
objPoint["x"]
和 objPoint["y"]
即可得到其中的x和y值
用“输出调试信息”查看结果
“点击图像”:“查找图像”、“模拟移动”、“模拟点击”三条命令的组合
4.OCR命令
很难直接获取微信中的聊天文字
UiBot采用百度云OCR,使用条件:
1.联网
2.向百度付费:免费通用文字识别每天5000次,证照等识别每天500次,超过了需要购买百度服务。
3.注册百度账号:需要自己注册百度云账号 及 百度云OCR服务的账号(一般称为Access Key和Secret Key),申请方法很简单,请点击这里查看我们的在线教程。
UiBot的OCR命令
红框里的命令类似于“图像”类中的“点击图像”、“鼠标移动到图像上”,“查找图像”命令,只不过不需要传入图像了,只需要在属性中标明要找的文字即可。
蓝框里的命令和绿框里的命令类似,只不过前者需要提供一个图像文件,后者需要提供一个窗口、以及窗口中的一个区域。
选择OCR目标
完成一条OCR命令
下面,再测试一下“图像特殊OCR识别”命令。所谓“特殊”,是指我们要测试的是某种特定的图像,如身份证、火车票等。假设我们在D:\\1.png
文件中保存了如下的图像:
要进行特殊OCR的图像
特殊OCR的属性设置
5.注意事项
无目标的命令,特别是它们所依赖的图像、OCR等命令,有以下的缺点:
- 速度慢
- 怕遮挡
- 依赖图像文件
- OCR需联网
图像、OCR命令技巧:
截图尽量小
区域尽量小
尽量保持分辨率和缩放比列一致
如,Windows 10操作系统分辨率和缩放比例:
使用图片时用绝对路径:
推荐把图片文件放res文件夹下,用@res"1.png"表示路径,@可以自动获取前缀路径。
五、语言参考
1.概述
UiBot是用来做RPA的编程语言,UB语言简单易用。
2.基本结构
UB语言是纯文本格式,UTF-8编码。
执行一个流程块的时候,从第一行开始执行,遇到函数定义暂时跳过,然后继续从函数结束后的一行开始执行。
推荐一行只写一个语句。如果一定要写多个语句,则用冒号分隔符(:)进行分隔。
需要折行,可以在任意语句中出现的逗号(,
)或二元运算符(“二元运算符”的概念请参考这里)之后直接折行,一定要在其他地方折行,则用反斜杠(\
)作为折行符号。例如:
Dim a= \ 1
注释:
单行注释://
多行注释:
/*
语句1
语句2
*/
UB语言中所有关键字、变量名、函数名均不区分大小写。
3.变量、常量和数据类型
1.数据类型:整数、浮点、布尔、字符串、函数、复合型和空值。
整数型:可以以十进制或者十六进制的方式表示,其中十六进制需加前缀 &H
或 &h
浮点数:可以用常规方式或者科学计数法表示。如 0.01
或者 1E-2
或者 1e-2
均代表同一个浮点数。
布尔型:True
或 False
(
不区分大小写
)
字符串:一对双引号("
) 或 一对单引号('
)包含,\t
代表制表符,用 \n
代表换行,用 \'
代表单引号,用 \"
代表双引号,用 \\
代表反斜杠本身。
字符串中间可以直接换行,无需增加任何其他符号,换行符也会作为字符串的一部分。
用前后各三个单引号('''
)来表示一个长字符串。在长字符串中,可以直接写回车符、单引号和双引号,无需用 \n
,\'
或者 \"
函数型的值只能是已经定义好的函数
复合型:数组、字典等
空值型: Null
,不区分大小写
a = 1 // a是整数型变量 a = &HFF // a还是整数型变量 a = True // a是布尔型变量。作为动态类型语言,a的类型可以随时变化 a = FALSE // a是布尔型变量,注意True和False都不区分大小写 a = 'UiBot' // a是字符串型变量 a = "UiBot RPA" // a是字符串型变量,字符串中可以换行 a = null // a是空值型变量,可以写为Null、NULL或null(不区分大小写)
2.变量和常量
变量定义:
Dim 变量名
定义变量并赋初值:
Dim 变量名=值
定义多个变量:
Dim 变量名1 = 值1, 变量名2 Dim 变量名1 = 值1, 变量名2 = 值2
标识符:有命名的东西(例如:变量、常量、函数等)
标识符以英文字母或_开头,可以包含数字、UTF-8编码中的其他语言字符(如汉字),变量名不区分大小写。
UB语言变量必须定义(除了For
语句中的循环变量、Try
语句中的异常变量、函数参数等)。
局部变量:函数内定义和使用
全局变量:函数外任意位置定义,全局使用。
3.复合类型
数组:
[值1, 值2, 值3 ]
字典:
{ “名字1”:值1, “名字2”:值2, “名字3”:值3 }
名字只能是字符串,值可以是任意类型
索引使用方括号[],多维数组或字典中的数组:
变量名[索引1][索引2]
Dim 变量 = [486, 557, 256] // 变量可以用中文命名,初值是一个数组 a = 变量[1] // 此时a被赋值为557 变量 = {"key1":486, "key2":557, "key3":256} // 变量的类型改为一个字典 a = 变量["key1"] // 此时a被赋值为486 变量["key4"] = [235, 668] // 往字典中增加一个新值,可以是一个数组 //此时,字典中的内容为 {"key1":486, "key2":557, "key3":256, "key4":[235, 668]} a = 变量["key4"][0] // 此时a被赋值为235
注:数组索引只能是整数,0开始。字典索引只能是字符串类型。
4.运算符和表达式
表达式:变量、常量和值用运算符和圆括号 ( )
连接到一起
Not
是一元运算符
- :
一元运算符,也可以用作二元运算符
其他都是二元运算符
注:=:出现在括号()内表示判断,单独语句表示赋值。
表达式常用于赋值语句,可以给某个变量赋值,其形式为:
变量名 = 表达式
数组、字典是引用类型,引用传递。
引用类型: a = [486, 557, 256] // a是一个数组 b = a // b是a的“别名” b[1] = 558 // 改变b里面的值,a里面的值也会跟着改变 c = a[1] // 此时c的值是558,而不是原来的557 变整数类型: a = 557 // 此时a被赋值为557(变为整数型) b = a // 此时b里面的值也是557,但和a分别保存 b = 558 // b里面的值发生改变,a的值不改变 c = a // 此时c的值仍然是原来的557,因为a不是字典、数组
5.逻辑语句
(1).条件分支语句
If 条件 语句块1 End If
If 条件 语句块1 Else 语句块2 End If
If 条件1 语句块1 ElseIf 条件2 语句块2 Else 语句块3 End If
示例:
// Time.Hour() 可以取得当前时间中的小时数 // TracePrint() 可以把指定的内容输出到UiBot的输出栏中 If Time.Hour() > 18 // 取得当前时间中的小时数 TracePrint("下班时间") // 如果大于18,则执行这里的语句 Else TracePrint("上班时间") // 如果不满足前面的条件,则执行这里的语句 End If
(2).选择分支语句
根据一定的条件,选择多个分支中的一个。先计算Select Case
后面的表达式
,然后判断是否有某个Case
分支和这个表达式
的值是一致的。如果没有一致的Case
分支,则执行Case Else
(如果有)后面的语句块。
Select Case 表达式 Case 表达式1, 表达式2 语句块1 Case 表达式3, 表达式4 语句块2 Case Else 语句块3 End Select
示例:
Select Case Time.Month() // 取得当前时间中的月份 Case 1,3,5,7,8,10,12 // 如果是1、3、5、7、8、10、12月 DayOfMonth = 31 // 当月有31天 Case 4,6,9,11 // 如果是4、6、9、11月 DayOfMonth = 30 // 当月有30天 Case Else // 如果是其他(也就是2月) DayOfMonth = 28 // 当月有28天(不考虑闰年的情况) End Select TracePrint(DayOfMonth)
(3).条件循环语句
在UB语言中,使用Do…Loop
语句来实现条件循环,即满足一定条件时,循环执行某一语句块。Do…Loop
语句有以下五种不同的形式,用法较为灵活:
- 前置条件成立则循环:先判断
条件
,条件
成立则循环执行语句块,否则自动退出循环。
Do While 条件 语句块 Loop
- 前置条件不成立则循环:和前一条相反,
条件
成立则退出循环,否则循环执行语句块。
Do Until 条件 //Until:到...为止 语句块 Loop
- 后置条件成立则循环:先执行语句块,再判断
条件
,条件
成立则继续循环执行语句块,否则自动退出循环。
Do 语句块 Loop While 条件
- 后置条件不成立则循环:先执行语句块,再判断
条件
,条件
成立则自动退出循环,否则继续循环执行语句块。
Do 语句块 Loop Until 条件
- 无限循环:该循环语句本身不进行任何条件的判断,需要在语句块中自行做判断,如果语句块中没有跳出循环的语句,则会无限的执行该循环
Do 语句块 Loop
示例:
Do Until Time.Hour() > 18 // 判断当前时间中的小时数,只要不大于18就循环 TracePrint("还没有到下班时间") // 每次循环,都会执行这里的语句 Delay(1000) // 每判断一次,休息一秒钟 Loop TracePrint("下班时间到啦") // 如果大于18,则跳出循环,执行这里的语句
(4).计次循环语句
计次循环语句主要用于执行一定次数的循环,其基本形式为:
For 循环变量 = 起始值 To 结束值 Step 步长 语句块 Next
起始值
、结束值
、步长
都只允许是整数型或者浮点数型;步长
可以省略,默认值为1。变量从起始值
开始,每循环一次自动增加步长
,直到大于结束值
,循环才会结束。
在计次循环语句中,循环变量
可以不用Dim
语句定义,直接使用,但在循环结束后就不能再使用了。
Dim count = 0 // 定义变量count For i=1 To 100 // 每次循环,变量i都会加1。这里变量i不需要定义 count = count + i Next TracePrint(count) // 这里会显示1+2+3+…+100的结果,即5050
(5).遍历循环语句
遍历循环语句可以用于处理数组、字典中的每一个元素。遍历循环语句有以下两种形式:
For Each 循环变量 In 数组或字典 语句块 Next
在这种形式的循环语句中,会自动遍历数组、字典中的每一个值,并将其置入循环变量
中,直到遍历完成为止。
或者:
在这种形式的循环语句中,会自动遍历数组、字典中的每一个索引和值,并将其分别置入循环变量1、循环变量2中,直到遍历完成为止。
和计次循环语句类似,在遍历循环语句中,循环变量
可以不用Dim
语句定义,直接使用,但在循环结束后就不能再使用了。
例如:
Dim days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] // 定义数组型变量days Dim count = 0 For Each i In days // 每次循环,变量i的值分别为days中的每个值 count = count + i // 把数组中的每个值依次加起来 Next TracePrint(count) // 这里会显示一年中每个月的天数的累加和,即365
(6).跳出语句
Break:只能出现在条件循环、计次循环或遍历循环等循环语句的内部语句块中,其含义是立即跳出当前循环。
Continue:只能出现在条件循环、计次循环或遍历循环等循环语句的内部语句块中,其含义是立即结束当前循环,并开始下一次循环。
Exit:自动结束整个流程 (不是当前流程块)
例如:
Dim days = { '一月':31, '二月':28, '三月':31, '四月':30, '五月':31, '六月':30, '七月':31, '八月':31, '九月':30, '十月':31, '十一月':30, '十二月':31 } // 定义字典型变量days For Each i,j In days // 每次循环,变量i, j分别为days中每个名字和值 If j Mod 2 = 0 // 如果j是偶数 Continue // 结束本次循环,开始下一次循环 End If TracePrint(i) // 把days中的名字(其值不是偶数)显示出来 Next
6.函数
函数的定义和调用没有先后关系,可以先出现调用,再出现定义。但函数必须定义在全局空间中,也就是说,函数定义不能出现在其他函数定义、分支语句、循环语句下面的语句块中。
- 无参数的函数
Function 函数名( ) 语句块 End Function
- 有参数的函数
Function 函数名(参数定义1, 参数定义2) 语句块 End Function
在函数定义中,要退出函数并返回,采用以下写法:
Return 返回值
Function Add(x, y=1) // 定义了两个参数的函数,第二个参数有默认值 Return x + y // 返回值为x+y的值 End Function
调用函数的格式如下:
返回 = 函数名(表达式1, 表达式2)
或者
函数名(表达式1,表达式2)
按照第一种格式调用,可以指定一个变量作为返回,当函数调用完成后,函数的返回值会自动赋值给这里的返回变量,调用者可以通过返回值,了解到函数调用的情况。此时,必须在被调用的函数名后面加圆括号。而当按照第二种格式调用时,调用者不需要返回值,则可以省略圆括号,使语句更符合自然语言习惯。
当调用时,相当于对函数中的参数进行了一次赋值运算,用表达式的值对其赋值。与赋值运算的规则相同,当表达式为一个独立的(没有使用任何运算符计算)数组、字典时,赋值操作只赋值其引用,也就是说,只是为变量增加一个“别名”。
调用函数时,传入的表达式的数量可以少于参数的数量,如果某个参数没有传入值,或者传入值为Null
,则采用其默认值,如果连默认值也没有,则其值自动为Null
。
a = Add(100) // 调用Add函数,第二个参数取默认值1,所以a的值是101 b = Add(100, 200) // 调用Add函数,指定了两个参数,所以b的值是300 Add 100, 200 // 调用Add函数,不关心返回值,所以可以不写括号
当函数定义完成后,其名称可以作为一个函数类型的常量使用,也可以把函数名称赋值给某个变量,用这个变量也可以调用这个函数。
例如,对于上面定义的函数Add
,可以按照如下的方式使用:
Dim Plus = Add TracePrint Plus(100, 200) // 相当于先调用了Add函数,再用其返回值调用了TracePrint函数,结果是300
7.其他
(1)多模块
UB语言支持多模块,可以用其他语言实现扩展模块,并在当前流程块中使用。目前支持以下几种类型的模块:1)UB语言的流程块;2)Python语言的模块;3)C/C++语言的模块;4).Net的模块;5)Lua语言的模块。不同的模块有不同的扩展名,去掉扩展名以后,剩下的文件名就是模块的名字。比如某个Python语言的模块,文件名为Rest.py,则其模块名为Rest。
在UB语言中,采用以下方式导入一个模块:
Import 模块名
注意这里的模块名的书写规则和变量名一致,不需要采用双引号,也不需要加扩展名。如Import Rest。UiBot在编译和运行时会自动按照Lua语言模块、C语言模块、.Net语言模块、Python语言模块、UB语言流程块的先后顺序,依次加上相应的扩展名进行查找。在Windows中,由于文件名不区分大小写,所以Import语句后面的模块名也可以不区分大小写。在其他操作系统中,需要注意模块名的大小写要和文件一致。
每个导入的模块,都会被放置在一个与模块名同名的“命名空间”中,可以通过下面这种方式来调用导入模块中的函数:
命名空间.函数名
对于Python、Lua语言的模块,只会保留其中的全局变量定义和函数定义,其他内容都会被忽略。对于C语言的模块和.Net模块,只能调用其中定义的函数。
如果要导入一个UB语言的流程块,则需要导入和被导入的流程块文件在同一个目录下。
导入UB语言的流程块之后,既可以调用被导入的流程块中定义的函数,又可以直接以流程块的名字作为函数名,直接运行这个流程块中的所有命令。
ABC()
例如,有一个流程块 ABC.task。在其他流程块中Import之后,直接采用下面的格式即可直接调用ABC.task(相当于运行了ABC.task这个流程块):
ABC.test()
(2)异常
作为动态类型语言,有很多错误在编译时难以检查,只能在运行时报错。而且,由于UiBot不强调运行速度,而更强调运行的稳定性,也会在运行时加入比较多的检查。当出错的时候,比较合适的报错手段是抛出异常。 比如,对于有目标命令(“有目标命令”的概念可以参考这里),在运行的时候,如果到了超时时间都不能找到目标,就会自动抛出一个异常。
除了自动抛出的异常之外,在流程块中,还可以采用Throw
语句抛出一个异常:
Throw 字符串
在抛出异常时,可以把异常相关信息以字符串的形式一起抛出,也可以省略这个字符串。
如果在流程块中没有对异常进行处理,当出现异常时,整个流程都会终止执行,并且把异常相关信息显示出来。如下图所示:
流程运行的时候出现异常
如果不希望流程在发生异常的时候终止,可以采用以下语句对异常进行处理:
Try 语句块 Catch 变量名 语句块 Else 语句块 End Try
如果在Try
后面的语句块中发生了异常,会跳到Catch
后面的语句块中执行。如果在Try
语句块中没有发生异常,且定义了Else
语句块(当然,也可以省略Else
语句块),则会跳到Else
语句块中执行。
Catch
语句后面的变量名可以省略。如果不省略,可以不用Dim
语句提前定义,当发生异常时,这个变量的值是一个字典,其中包含“File”、“Line”和“Message”三个字段,分别代表发生异常的文件名、发生异常的行号、异常包含的信息。
六、编写源代码
1.基本规则
UiBot的源代码视图遵循以下规则:
- 用一个源代码文件来表示一个流程块,源代码文件的扩展名默认是.task
- 用函数调用来表示一条命令
- 用函数调用时传入的参数,来表示命令的属性
- 用
Dim
语句来定义变量
从图中不难看出,“启动IE浏览器”的命令在源代码视图中实际上是对函数WebBrowser.Create
的调用;启动IE浏览器时设置的各项属性,都是函数调用中的变量,如"about:blank"
等;命令中使用到的变量,需要用Dim
语言定义。
可视化视图和对应的源代码视图
UiBot支持的命令非常丰富,在源代码视图中,这些命令都使用函数来表示。所以,UiBot实际上在UB语言的基础上,内置了一个很大的函数库。
其中,最常用的一部分函数是没有命名空间的,如Delay
函数;
其他函数都是包含一个命名空间的,如前面例子中的WebBrowser.Create
函数,其命名空间是WebBrowser
。对于有命名空间的函数,大部分都是通过UB语言中的多模块机制,利用一个模块中实现的,所以在使用前需要先用Import
语言导入相应的模块,例如WebBrowser.Create
函数,在使用前需要写Import WebBrowser
。
当然,还有几个基础功能,其命名空间是会自动Import
的,就不需要我们再做一次Import
了,包括Math
、Log
、Json
等。
UiBot支持的全部命令,其文档可以参考这里。在本文中,我们仅列出目前版本中已支持的主要命名空间及其功能概述,供读者参考。如对其中某个命名空间的功能有兴趣,再查阅文档不迟。注意,如前文所述,UB语言中的各种名字、关键字都不区分大小写,所以下表中列出的各个命名空间,都可以按全大写、全小写或各种大小写混合的方案进行书写。
比如,我们对Mouse
下面的功能感兴趣,一种方法是查阅文档,看看这个命名空间下面有哪些函数,每个函数有哪些参数。另外,如果您的手已经放在键盘上了,还有另一种更快捷的方法,如下所述:
- 在UiBot Creator的源代码视图中,随便找一个空行,然后键入
Mouse
(其实都不需要完整输入,只需要输入首字母m
,即可自动联想到相关的关键词,按上下箭头选择,并按回车确认即可) - 键入一个
.
符号,此时,会自动列出Mouse
命名空间下的所有函数 - 继续按上下箭头选择,每个选中的函数,都会出现其功能的简要说明,按回车确认要用的函数
- 再键入一个左括号
(
,此时,会自动列出这个函数的参数,并显示第一个参数的说明 - 此后,每输入一个参数,按逗号进行参数分隔后,会自动切换到后续参数的说明
上述过程大致如下图所示:
2.有命令目标
“点击目标”操作的源代码视图
第一行,以 #
符号开头,可以简单的认为是一种特殊的注释,对流程的运行没有影响,可以省掉。其实,在UiBot Creator中用浅灰色显示,也是建议您不要纠结于此。
第一行之后的内容其实是一个函数调用,调用的函数是Mouse.Action
,这个函数包含5个参数。但实际上,只有第一个参数是必须的,后面的参数都可以省略。我们不妨把可以省略的内容都去掉,只剩下下图所示的内容:
不难看出,函数只剩下了一个参数,这个参数是一个字典类型,代表了要点击的目标。当然,即便是这样简化,这个字典类型里面的内容也是很难手写出来的。怎么办呢?请注意,在源代码视图的上方,有“元素”、“图像”、“窗口”、“区域”四个按钮,分别还有对应的热键Alt+1、Alt+2、Alt+3、Alt+4(如下图)。由于我们需要用一个界面元素来作为命令的目标,所以,这里点击“元素”按钮。
源代码视图上方的快捷按钮点击后,UiBot Creator的界面暂时消失,出现了“目标选择器”,也就是红边蓝底的半透明遮罩。这个“目标选择器”的用法,和可视化视图中选取目标的方法一模一样,只需要把鼠标移动到目标上,待遮罩恰好遮住目标的时候,单击鼠标左键即可。如果您对“目标选择器”的操作还不熟悉,请回头复习前文中目标选取这部分内容。
目标编辑器的界面
选择目标之后,会弹出UiBot Creator的“目标编辑器”对话框,如下图所示。我们在前文中已经学习过如何使用目标编辑器来修改目标的特征,以避免造成目标的“错选”或“漏选”。这里的使用方法仍然与前文一致,仅有一点点细微的差别:右下角的按钮变成了“复制到剪贴板”。按下这个按钮,UiBot Creator会把目标的各个特征重新组合成一个字典类型的值,并把这个值以文本的形式复制到操作系统的剪贴板中。之后,只需要回到源代码视图,把剪贴板里的这段文本粘贴到函数调用Mouse.Action
中作为参数,即可完成这条命令的编写。
不妨把这段文本粘贴到记事本里,可以看到,其内容就是描述目标的字典类型的值:
{"wnd":[{"app":"explorer","cls":"Shell_TrayWnd"},{"cls":"Start","title":"开始"}]}
在UiBot中书写一条Mouse.Action()
函数调用,并把上述内容粘贴到圆括号里面,即可完成这条命令:
Mouse.Action({"wnd":[{"app":"explorer","cls":"Shell_TrayWnd"},{"cls":"Start","title":"开始"}]})
举一反三,我们试试做一点儿更多的操作。比如,把这个开始菜单按钮的图像,保存到一个图像文件里面去。用UiElement.ScreenShot
函数可以完成这个任务。这个函数有两个必选的参数,第一个参数仍然是指定界面元素作为目标,第二个参数是要保存的图像文件的路径。也就是说,第一个参数和前面Mouse.Action
的参数是完全一样的,把刚才复制到剪贴板的内容直接粘贴到这里就行;第二个参数写一个文件路径即可,比如"C:\\temp\\1.png"
。这里有两个值得注意的细节问题:
- 由于需要写文件,所以请注意,需要写到有权限的路径下。比如,UiBot默认不是以管理员账号启动的,所以诸如
"C:\\"
这样的路径就是不具有写权限的,但"C:\\temp"
具有写权限。 - 我们使用了字符串来表示文件路径,按照前文中UiBot的规定,字符串中要用转义字符
\\
来表示一个反斜杠\
,所以路径需要写为"C:\\temp\\1.png"
的格式。
保存并运行,即可看到开始菜单按钮的图像被存为一个文件。
回过头看看这段源代码,不难发现,“开始菜单按钮”这个目标被重复使用了两次,不好看。我们稍微改造一下,成为下面的样子:
Dim StartButton = {"wnd":[{"app":"explorer","cls":"Shell_TrayWnd"},{"cls":"Start","title":"开始"}]} Mouse.Action(StartButton) UiElement.ScreenShot(StartButton, "C:\\temp\\1.png")
这样看起来就清晰多了。