上一条博客【写文章-CSDN创作中心】我们对需要的环境进行了配置,也打开了浏览器进行对输入框操作,但是操作过程中遇到滑块,这一篇文章我们来解决这个问题
滑块的操作思路:
1、web自动化测试出现验证码【让滑块出现】
2、获取滑块和背景的图片地址
3、将背景图和滑块图下载到本地
4、人工智能匹配滑块验证码
5、缩放比例和移动距离算出来
6、模拟滑动解决
7、人工智能模拟和跟踪滑动轨迹
8、滑动失败重试机制
直接放代码,基础教学没有对代码过度抽取,很容易就看懂了,大佬勿喷
public class Test10 {
private final static String driver = "webdriver.chrome.driver";
private final static String chromeDriver = "C:\\Users\\d\\AppData\\Local\\Google\\Chrome\\Application\\chromedriver.exe";
private final static String openCvDll = "D:\\Program Files (x86)\\opencv\\build\\java\\x64\\opencv_java460.dll";
//网站需要的账号密码
private final static String usernmae = "****";
private final static String password = "*****";
static {
// 引入谷歌驱动 控制浏览器
System.setProperty(driver, chromeDriver);
// 引入opencv的dll
System.load(openCvDll);
}
public static void main(String[] args) throws InterruptedException {
System.out.println("正在打开浏览器");
//1、获取谷歌浏览器控制 打开浏览器
WebDriver driver = new ChromeDriver();
driver.manage().window().maximize();//浏览器最大化
//2、超时等待30秒
Duration duration = Duration.ofSeconds(30);
driver.manage().timeouts().implicitlyWait(duration);
//3、跳转到智慧树网址
driver.get("https://passport.zhihuishu.com/login?service=https://onlineservice-api.zhihuishu.com/login/gologin#signin");
//4、解决机器打开验证不成功【脚本打开和人为打开浏览器会有一个标识,通过这个代码进行修改】
((JavascriptExecutor) driver).executeScript("Object.defineProperties(navigator,{ webdriver:{ get: () => false } })");
//5、获取到账号和密码的输入框 lUsername 并填写内容
driver.findElement(By.id("lUsername")).sendKeys(usernmae);
driver.findElement(By.id("lPassword")).sendKeys(password);
//6、找到登录按钮模拟点击
driver.findElement(By.className("wall-sub-btn")).click();
//7、这个时候可能会弹出来滑块
Boolean flag = true;
int i = 1;
do {
System.out.println("第" + i++ + "次进行验证");
//8、这时候可能有滑块出现yidun_slider
WebElement sliderBJ = null;
WebElement sliderHK = null;
try {
//9、如果没拿到,说明直接登录了,没有触发出来滑块
sliderBJ = driver.findElement(By.className("yidun_bg-img"));
sliderHK = driver.findElement(By.className("yidun_jigsaw"));
} catch (Exception e) {
e.printStackTrace();
}
//10、解决图片下载不了的问题
TimeUnit.SECONDS.sleep(1);
//11、如果不为空需要处理滑块
if (sliderBJ != null && sliderHK != null) {
//11.1、先得到距离,这里需要opencv 先搭建一下
//11.2、获取到背景图的地址和滑块的地址
String srcBJ = sliderBJ.getAttribute("src");
String srcHK = sliderHK.getAttribute("src");
//11.3、拿到url后缀
String houZhui = srcBJ.substring(srcBJ.lastIndexOf("."));
String houZhuiHK = srcHK.substring(srcBJ.lastIndexOf("."));
//11.4、将图片下载到本地
downloadPicture(srcBJ, "D:\\img\\beijing" + houZhui);
downloadPicture(srcHK, "D:\\img\\huakuai" + houZhuiHK);
//11.5、从本地读取背景原图
Mat src = Imgcodecs.imread("D:\\img\\beijing" + houZhui, Imgcodecs.IMREAD_GRAYSCALE);
Mat srcBenDiHK = Imgcodecs.imread("D:\\img\\huakuai" + houZhuiHK, Imgcodecs.IMREAD_GRAYSCALE);
//11.6、创建一个新的背景图,方便做标记
Mat clone = src.clone();
Mat result = new Mat();
//11.7、匹配小图在大图中的位置 用标准模式去比较 然后把返回结果给result
Imgproc.matchTemplate(src, srcBenDiHK, result, Imgproc.TM_CCORR_NORMED);
Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1, new Mat());
//11.8、获取匹配结果坐标
Core.MinMaxLocResult minMaxLocResult = Core.minMaxLoc(result);
Point maxLoc = minMaxLocResult.maxLoc;
//11.9、在图上做标记
Imgproc.rectangle(clone, maxLoc,
new Point(maxLoc.x + srcBenDiHK.cols(), maxLoc.y + srcBenDiHK.rows()),
new Scalar(0, 255, 0));
Imgcodecs.imwrite("D:\\img\\close.jpg", clone);
//11.10、将背景图存储在本地
Imgcodecs.imwrite("D:\\img\\beijing" + houZhui, src);
Imgcodecs.imwrite("D:\\img\\huakuai" + houZhuiHK, srcBenDiHK);
double distance = maxLoc.x - maxLoc.y;
//11.11、模拟移动
move(driver, sliderHK, (int) distance + 20);
//11.12、移动后看看是否还存在不
try {
TimeUnit.SECONDS.sleep(2);
driver.findElement(By.className("yidun_bg-img"));
} catch (Exception e) {
flag = false;
System.out.println("验证成功");
}
}
} while (flag);
System.out.println("循环结束,验证成功");
}
/*
*
* 下载图片到本地
* */
private static void downloadPicture(String urlList, String path) {
URL url = null;
try {
url = new URL(urlList);
DataInputStream dataInputStream = new DataInputStream(url.openStream());
FileOutputStream fileOutputStream = new FileOutputStream(new File(path));
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = dataInputStream.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
fileOutputStream.write(output.toByteArray());
dataInputStream.close();
fileOutputStream.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 模拟人工移动
*
* @param driver
*/
public static void move(WebDriver driver, WebElement element, int distance) throws InterruptedException {
int randomTime = 0;
if (distance > 90) {
randomTime = 250;
} else if (distance > 80 && distance <= 90) {
randomTime = 150;
}
List<Integer> track = getMoveTrack(distance - 2);
int moveY = 0;
try {
//初始化鼠标对象
Actions actions = new Actions(driver);
//鼠标按住左键不动
actions.clickAndHold(element).perform();
Thread.sleep(200);
for (int i = 0; i < track.size(); i++) {
//把元素滑动到执行坐标
actions.moveByOffset(track.get(i), moveY).perform();
Thread.sleep(new Random().nextInt(300) + randomTime);
}
Thread.sleep(200);
actions.release(element).perform();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 根据距离获取滑动轨迹
*
* @param
* @return
*/
public static List<Integer> getMoveTrack(int distance) {
List<Integer> track = new ArrayList<>();// 移动轨迹
Random random = new Random();
int current = 0;// 已经移动的距离
int mid = (int) distance * 4 / 5;// 减速阈值
int a = 0;
int move = 0;// 每次循环移动的距离
while (true) {
a = random.nextInt(10);
if (current <= mid) {
move += a;// 不断加速
} else {
move -= a;
}
if ((current + move) < distance) {
track.add(move);
} else {
track.add(distance - current);
break;
}
current += move;
}
return track;
}
}
因为贴出来的代码里面账号密码不是正确的,提示错误就可以了,具体的看操作流程
opencv的安装流程在这文章里面没有,需要自己单独安装或者评论滴滴