java OpenCV挑战极验滑动拼图验证码
一丶解析验证码组成
从上面三张图来看,极验滑动拼图验证码是由一个小的拼图和一个大的背景图组成,拼图的形状各式各样,背景图中有一个阴影缺口,与拼图形状一致。
这里我们使用F12大法打开浏览器控制台,观察一下验证码的页面结构。
通过观察可以看到,验证码所包含的图片均以<canves>
画布的形式呈现在页面中,且有三张图片,且第三张图片被加上了属性style=“display: none;”,即为隐藏不显示。那么我们修改下页面代码,看下这张图究竟是什么。
修改完代码发现,这不就是完整的背景图嘛。那么根据上面的命名来看,基本可以确定这三张图分别是什么了。
-
第一张class为geetest_canvas_bg geetest_absolute,可以确定为带缺口的背景图。
-
第二张class为geetest_canvas_slice geetest_absolute,可以确定为拼图。
-
第三张便是完整的图片。
二丶分析出破解思路
- 首先根据这个验证码的组成,来分析一下我们人要做的事情:
按照正常的手动操作流程来看,我们需要看出背景图中与拼图对应的阴影缺口的位置,然后鼠标按住下方滑块来把拼图对正到缺口位置来完成验证。
- 然后根据人要做的事情,来分析一下程序要做的事情:
根据分析得出下面几个步骤:
1.获取到两张图片(带缺口背景图、完整背景图)
2.处理图片,得到阴影位置并计算滑动距离
3.根据滑动距离模拟滑动
三丶具体操作步骤
1丶获取到两张图片
由于这里的图片都是通过canvas
画布呈现的,我们可以通过执行js代码来生成图片。
可以参考《如何抓取canvas画布中的图片》。
2丶处理图片,计算滑动距离
通过第一步得到的两张图片可以看出,两张图有两处不同的地方,一处差异不大,一处差异较大,我们可以通过比较每一个像素点的差异度来确定阴影缺口的位置。缺口的位置横坐标减去小图距离边框的距离即为滑动距离。
以下是关键部分代码:
private final String INDEX_URL = "https://www.geetest.com/Register";
// 延时加载
private static WebElement waitWebElement(WebDriver driver, By by, int count) throws Exception {
WebElement webElement = null;
boolean isWait = false;
for (int k = 0; k < count; k++) {
try {
webElement = driver.findElement(by);
if (isWait)
System.out.println(" ok!");
return webElement;
} catch (org.openqa.selenium.NoSuchElementException ex) {
isWait = true;
if (k == 0)
System.out.print("waitWebElement(" + by.toString() + ")");
else
System.out.print(".");
Thread.sleep(50);
}
}
if (isWait)
System.out.println(" outTime!");
return null;
}
/**
* 计算需要平移的距离
*
* @param driver
* @param fullImgPath完整背景图片文件名
* @param bgImgPath含有缺口背景图片文件名
* @return
* @throws IOException
*/
public static int getMoveDistance(WebDriver driver, String fullImgPath, String bgImgPath) throws IOException {
File fullFile = new File(fullImgPath);
File bgFile = new File(bgImgPath);
try {
BufferedImage fullBI = ImageIO.read(fullFile);
BufferedImage bgBI = ImageIO.read(bgFile);
for (int i = 0; i < bgBI.getWidth(); i++) {
for (int j = 0; j < bgBI.getHeight(); j++) {
int[] fullRgb = new int[3];
fullRgb[0] = (fullBI.getRGB(i, j) & 0xff0000) >> 16;
fullRgb[1] = (fullBI.getRGB(i, j) & 0xff00) >> 8;
fullRgb[2] = (fullBI.getRGB(i, j) & 0xff);
int[] bgRgb = new int