Java + Selenium + OpenCV解决自动化测试中的滑块验证
最近工作过程中,一个常用的被测网站突然增加了滑块验证环节,导致整个自动化项目失效了。
为了解决这个滑块验证问题,在网上查阅了一些资料后,总结并实现了解决方案,现记录如下。
1、滑块验证思路
被测对象的滑块对象长这个样子。相对而言是比较简单的一种形式,需要将左侧的拼图通过下方的滑块进行拖动,嵌入到右侧空槽中,即完成验证。
要自动化完成这个验证过程,关键点就在于确定滑块滑动的距离。
根据上面的分析,验证的关键点在于确定滑块滑动的距离。但是看似简单的一个需求,完成起来却并不简单。
如果使用自然逻辑来分析这个过程,可以拆解如下:
1. 定位到左侧拼图所在的位置,由于拼图的形状和大小固定,那么其实只需要定位其左边边界离背景图片的左侧距离。(实际在本例中,拼图的起始位置也是固定的,节省了不少工夫)
2. 定位到右侧凹槽所在位置,同样其形状和大小是固定的,那么只需要定位其左边边界离背景图片的左侧距离。
3. 用2中探测到的距离减去1中的距离,既是滑块需要被拖动的距离。
要完成上述的探测计算,首先我们想到的是使用元素定位的方法定位到拼图和凹槽的位置。
然而这一想法是不可行的,原因在于这个验证模块是使用两个canvas即画布元素实现的:
拼图和凹槽都是“画”在画布上的,其本身并不是一个页面元素,不能使用元素定位的方法。
因此我们考虑使用图片解析的方法,分析画布图像本身,来确定相应图形的位置。
2、使用OpenCV进行图片解析
这里我们将引入OpenCV库,来帮我完成图片解析过程:
OpenCV是一个基于Apache2.0许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上。
它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。
OpenCV用C++语言编写,它具有C ++,Python,Java和MATLAB接口,并支持Windows,Linux,Android和Mac OS,OpenCV主要倾向于实时视觉应用,并在可用时利用MMX和SSE指令, 如今也提供对于C#、Ch、Ruby,GO的支持。
2.1 OpenCV引入项目
1:下载 OpenCV
进入到官网 https://opencv.org/releases/ 下载对应系统的 openCV 软件包后,解压放置到本地。
使用Maven依赖并不能引入正确的OpenCV外部依赖,这里需使用外部
2:工程中添加 jar 包
Intellij 中选择 File -> Project Structure -> Modules -> Dependencies
点击 add -> JARS or directories... 选择
3. 新建滑块验证工具类,引入OpenCV动态链接库文件:opencv_java450.dll
public class slideUtil { public static String dllPath = "D:\\AutoTest\\src\\main\\resources\\lib\\opencv\\opencv_java450.dll"; public static void main(String[] args) { //getDistance();//调试用的main方法,调用一个getDistance方法,获取拼图和凹槽之间的距离,返回double类型数值。
}
2.2 实现图片解析,计算所需距离
由于本项目的特点,拼图的形状和位置是固定的,首先我们将拼图和凹槽图片下载到本地,方便后续处理。(其它项目可能出现图片形状不固定的情况,可以直接用selenium实时下载图片,这过程比较简单,因此不赘述)。
下载完的图片如下:
凹槽图片:
拼图图片:
下面直接上代码再做说明:
public static double getDistance(){ // 加载OpenCV本地库
System.load(dllPath); //System.loadLibrary(Core.NATIVE_LIBRARY_NAME); //对拼图图形进行处理,存储为Mat类型① Mat slideBlockMat=Imgcodecs.imread("slide_blk.png");//由于本项目的特点,拼图的形状和位置是固定的,因此直接将拼图图片保存到本地进行使用了 //Step1、灰度化图片② Imgproc.cvtColor(slideBlockMat,slideBlockMat,Imgproc.COLOR_BGR2GRAY); imwrite("cvt_blk.png",slideBlockMat); //Step2、去除周围黑边 for (int row = 0; row < slideBlockMat.height(); row++) { for (int col = 0; col < slideBlockMat.width(); col++) { if (slideBlockMat.get(row, col)[0] == 0) { slideBlockMat.put(row, col, 96); } } } imwrite("nsr_blk.png",slideBlockMat); //Step3、转黑白图 Core.inRange(slideBlockMat, Scalar.all(96), Scalar.all(96), slideBlockMat); imwrite("ezh_blk.png",slideBlockMat);
//对滑动背景图进行处理③ Mat slideBgMat = Imgcodecs.imread("slide_bg.png");//背景凹槽图片需要动态获取,见下面的解析 //Step1、灰度化图片④ Imgproc.cvtColor(slideBgMat,slideBgMat,Imgproc.COLOR_BGR2GRAY);
imwrite("hdh_bg.png",slideBgMat); //Step2、二值化
//Core.inRange(slideBgMat, Scalar.all(96), Scalar.all(96), slideBgMat); Imgproc.threshold(slideBgMat,slideBgMat,127,255, Imgproc.THRESH_BINARY);
imwrite("ezh_bg.png",slideBgMat); Mat g_result = new Mat(); /*
* 将凹槽背景和拼图图形进行匹配⑤
*/ Imgproc.matchTemplate(slideBgMat,slideBlockMat,g_result, Imgproc.TM_CCOEFF_NORMED); Point matchLocation= Core.minMaxLoc(g_result).maxLoc; //返回匹配点的横向距离 System.out.println(matchLocation.x);
return matchLocation.x;
}
2.3 算法解析说明
①什么是Mat类型:
灰度化: 去黑边:
二值化:
最终的目的在于将图形转化为黑白分明的图形,便于后续匹配。
③本项目中,由于背景凹槽图片,凹槽的位置是动态的,所以需要实时动态获取:(如果遇到拼图也需要动态获取,可以同样处理)
WebElement bg_canvas = driver.findElement(slide_ver_bg_by);//元素定位,定位到背景图片 Object base64 = ((JavascriptExecutor) driver)
.executeScript("return arguments[0].toDataURL('image/png').substring(21);", bg_canvas);//页面元素转Base64
String base64Str = base64.toString();
generateImage(base64Str , "slide_bg.png");// 将base64把字符串装换成图片
④对于slide_bg.png的处理经过了以下过程:
灰度化: 二值化:
这里省略了去黑边这一过程,因为实践发现,经过上述两部后,我们已经能够进行较为准确的图片匹配了。
⑤matchTemplate:在模板和输入图像之间寻找匹配,获得匹配结果图像
esult:保存匹配的结果矩阵
TM_CCOEFF_NORMED标准相关匹配算法
minMaxLoc:在给定的结果矩阵中寻找最大和最小值,并给出它们的位置
3、Selenium处理滑块滑动
Selenium的滑块处理是库里的标准玩法,使用actions类或者javaScript的方式都可以实现,本例采用的是actions类方法:
public void slide_verify(WebDriver driver) throws InterruptedException { double slideDistance = getDistance();//此处就是调用2中的OpenCV计算拼图和凹槽距离 System.out.println("滑动距离是" + slideDistance); WebElement dragElement = driver.findElement(slide_obj_by);//定位到滑块 Actions actions = new Actions(driver); actions.clickAndHold(dragElement);//模拟鼠标动作,按住滑块
Thread.sleep(300);
//滑动,分两次进行①
actions.moveByOffset(((int)slideDistance - 11)/2,0);
Thread.sleep(1000);
actions.moveByOffset(((int)slideDistance - 11)/2,0);
Thread.sleep(500); actions.release();
actions.perform(); }
①这里进行滑动时,首先滑动距离之所以要减去11,是因为本例中拼图的初始位置固定离整体图形的左边距是11.
分两次滑行并且中间sleep了一个时间,是为了防止全匀速拖动而被识别为机器人。
其它文章中有提到使用比较复杂的拖动轨迹算法,本项目中实践得知,滑动轨迹并没有太重要,分两次拖动就可以了,没必要复杂化。
4、最终效果
最终的滑动效果,因为被测网站的敏感性就不放上来了,最终实现成果是较为理想的。
希望这篇文章能够帮助到有需要的人。
Java + Selenium + OpenCV解决自动化测试中的滑块验证的更多相关文章
- java+Selenium+TestNg搭建自动化测试架构(1)实现代码和数据的分离
1.主要介绍介绍Java+Selenium+POM的自动化测试框架的搭建,第一个首先实现代码和账号URL等信息的分离.第二点支持跨浏览器,通过读取配置文件的方式实现. 1)将账号URL等信息添加在pr ...
- JAVA 自定义注解在自动化测试中的使用
在UI自动化测试中,相信很多人都喜欢用所谓的PO模式,其中的P,也就是page的意思,于是乎,在脚本里,或者在其它的page里,会要new很多的page对象,这样很麻烦,前面我们也讲到了注解的使用,很 ...
- 基于Java+Selenium的WebUI自动化测试框架(六)---浏览器初始化
本篇我们来讨论,如何写一个浏览器初始化的类.在写之前,先思考一下,我们需要一个什么样的初始化? 先来看看使用原生的Java + selenium是怎么做的.(以firefox为例) System.se ...
- 基于Java+Selenium的WebUI自动化测试框架(一)---页面元素定位器
对于自动化测试,尤其是UI的自动化测试.是很多做黑盒功能测试的同学,入门自动化测试一个最为直观的或者说最容易理解的途径之一. 对于手工测试和自动化测试的优劣,网上有很多论述,在这里不作展开讨论.但是, ...
- java+Selenium+TestNg搭建自动化测试架构(3)实现POM(page+Object+modal)
1.Page Object是Selenium自动化测试项目开发实践的最佳设计模式之一,通过对界面元素的封装减少冗余代码,同时在后期维护中,若元素定位发生变化,只需要调整页面元素封装的代码,提高测试用例 ...
- 基于Java+Selenium的WebUI自动化测试框架(十四)-----使用TestNG的Sample
到目前为止,我们所写的东西,都是集中在如何使用Selenium和Java来定位和读取元素.那么,到底如何具体开展测试,如何实现参数化,如何实现判定呢?下面,我们来看看Java应用程序的测试框架吧. 当 ...
- Java&Selenium&TestNG&ZTestReport 自动化测试并生成HTML自动化测试报告
一.摘要 本篇博文将介绍如何借助ZTestReport和HTML模版,生成HTML测试报告的ZTestReport 源码Clone地址为 https://github.com/zhangfei1984 ...
- java+Selenium+TestNg搭建自动化测试架构(2)实现跨浏览器功能
1.切换浏览器类:其中包含了切换浏览器的方法,以及关闭浏览器,设置等待时间,以及重写的断言方法 package com.rrx.framework; import java.io.IOExceptio ...
- 基于Java+Selenium的WebUI自动化测试框架(十)-----读取Excel文件(JXL)
之前,我们使用了读取XML文件的方式来实现页面元素的读取,并做成了基础页面类.下面,我们来进行一些扩展,通过Excel来读取页面元素. Excel的使用,大多数人应该都不陌生.那么Java读取Exce ...
随机推荐
- Vue.js 3.x 中跨层级组件如何传递数据?
provide/inject 基本用法 在 Vue.js 中,跨层级组件如果想要传递数据,我们可以直接使用 props 来将祖先组件的数据传递给子孙组件: 注:上图来自 Vue.js 官网:Prop ...
- 【Hadoop】10、Flume组件
目录 Flume组件安装配置 1.下载和解压 Flume 2.Flume 组件部署 3.使用 Flume 发送和接受信息 Flume组件安装配置 1.下载和解压 Flume # 传Flume安装包 [ ...
- axios源码解析 - 请求拦截器
axios请求拦截器,也就是在请求发送之前执行自定义的函数. axios源码版本 - ^0.27.2 (源码是精简版) 平时在业务中会这样去写请求拦截器,代码如下: // 创建一个新的实例 var s ...
- 深入C++06:深入掌握OOP最强大的机制
深入掌握OOP最强大的机制 1. 继承的基本意义 类与类之间的关系:①组合:a part of ... 一部分的关系:②继承: a kind of ... 属于同一种的关系: 继承的本质:a. 代码的 ...
- Spring事务源码解读
一.Spring事务使用 1.通过maven方式引入jar包 <dependency> <groupId>com.alibaba</groupId> <art ...
- 个人冲刺(五)——体温上报app(二阶段)
冲刺任务:完成用户登录和随机验证码功能 loginActivity.java package com.example.helloworld; /** * 纯粹实现登录注册功能,其它功能都被注释掉了 * ...
- 命令行传参——JavaSE基础
命令行传参 可以在运行一个程序时再传递给它消息,可以依靠命令行传参给mian()函数实现 public class CommandLine(){ public static void main(Str ...
- JuiceFS V1.0 RC1 发布,大幅优化 dump/load 命令性能, 深度用户不容错过
各位社区的伙伴, JuiceFS v1.0 RC1 今天正式发布了!这个版本中,最值得关注的是对元数据迁移备份工具 dump/load 的优化. 这个优化需求来自于某个社区重度用户,这个用户在将亿级数 ...
- iNeuOS工业互联网操作系统,增加搜索应用、多数据源绑定、视图背景设置颜色、多级别文件夹、组合及拆分图元
目 录 1. 概述... 2 2. 搜索应用... 2 3. 多数据源绑定... 3 4. 视图背景设置颜色... 4 5. 多级别文件夹 ...
- 雪花算法及微服务集群唯一ID解决方案
雪花算法(SnowFlake) 简介 现在的服务基本是分布式.微服务形式的,而且大数据量也导致分库分表的产生,对于水平分表就需要保证表中 id 的全局唯一性. 对于 MySQL 而言,一个表中的主键 ...