Jython+sikulix实现GUI自动化

Jython+sikulix实现GUI自动化

sikulix是一个基于openCV实现的的GUI自动化的库,可以模拟鼠标、键盘等操作,用来操控你在电脑桌面上看到的一切,大概的实现方式如下

1、sikulix会截图当前桌面放到内存中

2、调用方传入一个特征图片,在刚刚的桌面截图中查找该特征图片

3、找到后返回特征图片位置,并在桌面执行鼠标或是键盘操作

所有图片相关的操作计算都是基于openCV的,而且sikulix还支持简单的OCR,可以识别低干扰下的文字。

最新版本1.1.1更是支持了vnc远程操作,可以实现远程分布式的异步操作,让测试更高效。不过楼主在使用过程中发现了一个bug,vnc远程对象不兼容特殊按键的操作,已经上报给sikulix社区并且开发人员已经fixed,可点击bug链接查看详情

Jython是一种完整的语言,而不是一个Java翻译器或仅仅是一个Python编译器,它是一个Python语言在Java中的完全实现。Jython也有很多从CPython中继承的模块库。最有趣的事情是Jython不像CPython或其他任何高级语言,它提供了对其实现语言的一切存取。所以Jython不仅给你提供了Python的库,同时也提供了所有的Java类,这使其有一个巨大的资源库。以上引自百度百科。

其实简单理解jython就是可以通过python语法编程并且可以调用java库的语言,它本身也有pip等包管理工具,跟python使用方法一样,只是有些C实现的python库它不支持,所以jython本身对python的支持还不是特别完美,不过已然够用。大概执行过程是py文件通过jython解释器编译为java字节码.class文件,然后再扔给JVM去执行。这里顺便提一下,只要是符合java虚拟机规范的字节码class文件都可以交由JVM去执行,比如Jruby、Groovy也都是先生成class文件然后基于JVM去执行。

下面开始进入正题!

1、jython安装配置

下载地址:http://www.jython.org/downloads.html

首先,在安装jython之前要先安装jdk7或8,并且配置好JAVA_HOME和Path环境变量,具体请自行百度。jython安装包是一个可执行的jar包,可以双击直接打开GUI图形向导安装,但是楼主推荐在cmd通过java -jar方式运行,因为这样在安装过程的任何报错信息都可以看到,方便确认是否真的安装成功。

一步步安装成功后,然后在IDE中配置Jython路径,楼主用的eclipse,配置方式window-preference-PyDev-Interpreters,如下图:

这样jython环境就配置好了

Tips:如果想要在jython中安装python包,进入C:\jython2.7.0\bin,运行pip insatll packagename即可,方法跟python是一样样的

2、sikulix安装配置

下载地址:http://sikulix.com/

sikulix本身也是一个可执行的jar包,如果直接双击运行的话会安装一个sikulix-IDE,可以在上边编写简单sikulix脚本,局限性较大,一般都是程序中引用该包,这样更加灵活。在eclipse中右键工程目录,选择properties,按照下图配置即可

sikulix包的引用配置好后,在py程序中引用方式如下

如果要实现vnc远程连接的话,需要先配置个vncserver,推荐使用realVNC,下载地址:https://archive.realvnc.com/download/open/,配置很简单,都是图形界面的,这里就不讲了

3、楼主专门写了个QQ登陆的demo供参考,从字面意上挺好理解,详细使用文档请参考官方文档

login需要的控件图片如下所示:

#coding:utf-8
'''
@author: yinzhixin
@decription:  blablablabla
'''
import sys
import os
import time
from tomorrow import threads
import org.sikuli.script.SikulixForJython
from sikuli import *

con = {
    "win7":{"ip":"127.0.01", "port":5900},
    "xp":{"ip":"192.168.0.124", "port":5900}
    }

class VncBase(object):
    #修改图片匹配相似度,默认相似度为0.7
    Settings.MinSimilarity = 0.5
    #打开调试开关
    Debug.on(4)
    
    def __init__(self,con = None):
        '''
        @param: con-vncserver连接信息
        @decription: 如果传入连接串则远程vnc连接,默认为本地操作
        '''
        self.con = con
        self.vnc = self._vnc()
        self.png_path = os.path.dirname(__file__)
        
    def _vnc(self):
        vnc = vncStart(**self.con) if self.con else Screen()
        return vnc
            
    def _featureCheck(self, feature):
        '''
        @param: feature-特征图片
        @decription: 检查特征图片是否存在于当前屏幕中,不存在则退出程序
        '''
        if self.vnc.exists(feature, 10):
            return self.vnc.find(feature)
        else:
            self.stopVnc()
            os._exit()
            
    @threads(1)
    def login(self,username, passwd):
        '''
        @decription: 登陆操作, 各方法中封装的click、doubleClick、type等
                     都是sikulix内置的vnc或者screent对象的方法
        '''
        self.showDesktop()
        login_png = os.path.join(self.png_path, "login")
        #sikulix自带函数,修改默认图片搜索路径,默认为sikulix库文件所在路径
        setBundlePath(login_png)
        self._doubleClick("qq.png")
        self._type("login_username.png", username)
        self._type("login_passwd.png", passwd)
        self._click("login_loginbutton.png")
        return True
        
    def logout(self):
        pass       
    
    def _click(self, control, flag=1):
        control = self._featureCheck(control)
        if flag == 1:
            control.click()
        else:
            control.doubleClick()
    
    def _doubleClick(self, control):
        self._click(control, 2)

    def _type(self,control,text):
        control = self._featureCheck(control)
        self.vnc.type(control, text)
    
    def showDesktop(self):
        '''
        返回桌面ִ
        '''
        self.vnc.keyDown(Key.WIN)
        self.vnc.type("d")
        self.vnc.keyUp(Key.WIN)
    
    def stopVnc(self):
        '''
        @decruption: 关闭vnc连接,程序执行完sikulix默认会自动关闭,
                     但是异常情况下需要手动释放连接
        '''
        if self.vnc:
            self.vnc.stop()

class User(VncBase):
    pass

if __name__ == "__main__":
    user1 = User()
    user1.login("123456", "123456")
    #user2 = User(con["xp"])
   # user2.login("123456", "123456")     

That’all!有什么不对的地方,欢迎指正!

Comments are closed.