网易易盾——滑动拼图验证码

问题和思路

滑动拼图验证码

如何使用自动化手段模拟人为操作完成该验证码的验证流程?

思路:计算拼图与缺口之间的距离,通过控制拖动的方式,将拼图拖动至缺口位置,确保误差越小越好。

尝试解决

  1. 首先需要计算距离,可以采用opencv对图像进行处理,其中最主要的是利用matchTemplate函数计算出,拼图与缺口之间的位置,从而获得距离。
// 滑块图片
Mat slideBlockMat = Imgcodecs.imread(touchFile.getAbsolutePath(), 0);
Size size = new Size(3, 3);
Imgproc.GaussianBlur(slideBlockMat, slideBlockMat, size, 0);
Imgproc.Canny(slideBlockMat, slideBlockMat, 50, 150);
// 背景缺口图片
Mat bgBlockMat = Imgcodecs.imread(bgFile.getAbsolutePath(), 0);
Imgproc.GaussianBlur(bgBlockMat, bgBlockMat, size, 0);
Imgproc.Canny(bgBlockMat, bgBlockMat, 50, 150);
// 将滑块与背景进行匹配
Mat resultMat = new Mat();
Imgproc.matchTemplate(slideBlockMat, bgBlockMat, resultMat, Imgproc.TM_CCOEFF_NORMED);
org.opencv.core.Point matchLocation = Core.minMaxLoc(resultMat).maxLoc;
// 需要滑动的距离
double distance = matchLocation.x;
  1. 得到距离之后,需要通过模拟人为拖动的行为方式,将拼图拖动至缺口处。
// 获取拼图元素的大小
Dimension touchEleSize = touchEle.getSize();
// 根据拼图大小调整实际拖动的距离
distance = distance + (int) (touchEleSize.getWidth() / 4.0) - 5;
// 记录某时间内拖动的距离
List<Double> tracks = new ArrayList<>();
List<Double> offsets = new ArrayList<>();
offsets.add(0d);
// 拖动完成秒数
double second = (int) (distance / 100) + 1.0;
// 通过公式计算出每0.1秒需要滑动的距离,从而模拟人为拖动轨迹
for (double i = 0d; i < second; i += 0.1) {
double offset = Math.round((1 - Math.pow(1 - (i / second), 4)) * distance);
tracks.add(offset - offsets.get(offsets.size() - 1));
offsets.add(offset);
}

fullscreen();
touchEle = webDriver.findElement(touchBy);
Rectangle rect = touchEle.getRect();

// 通过操作鼠标来完成拖动操作
AutoItX autoItX = new AutoItX();
autoItX.sleep(3000);
autoItX.mouseMove(rect.getX() + touchEleSize.getWidth() / 2, rect.getY() + touchEleSize.getHeight() / 2);
autoItX.mouseDown("left");
tracks.forEach(move -> {
autoItX.mouseMove(autoItX.mouseGetPosX() + move.intValue(), autoItX.mouseGetPosY(), 5);
autoItX.sleep(10);
});
autoItX.sleep(1500);
autoItX.mouseUp("left");
exitFullscreen();

实际效果