java、selenium、图片滑块验证,底部附本地可测试代码
阅读原文时间:2022年05月11日阅读:1

准备

本地Chrome版本对应WebDriver驱动:http://chromedriver.storage.googleapis.com/index.html

maven包


org.seleniumhq.selenium selenium-java 3.9.0

思路

1、获取背景图片元素

WebElement bimg= webDriver.findElement(By.xpath(""));

xpath:f12定位背景图片元素右键copy--->Copy Xpath
截图指定元素将图片下载到本地,这里之所以不通过url获取图片是因为图片大小与图片在页面实际大小可能并不一致,我们需要操作页面所以以页面为准。

File bFile = new File("C:\\Users\\jyk\\Desktop\\bFile.jpg");

FileTool.screenshotsWebElement(bimg, bFile);

/**
* 元素截图
* @param webElement
* @param out
* @throws IOException
*/
public static void screenshotsWebElement(WebElement webElement, File out) throws IOException {
FileInputStream fis = null;
FileOutputStream fos = null;
File screenshotAs = webElement.getScreenshotAs(OutputType.FILE);
//读取文件
fis = new FileInputStream(screenshotAs);
int available = fis.available();
byte[] bytes = new byte[available];
fis.read(bytes);
//输出文件
fos = new FileOutputStream(out);
fos.write(bytes);
fis.close();
fos.close();
}

定义正则,难点之一,需要自己去找规律设置对应的正则

//正则
//101,010
String z1 = "01{54}0";
String z2 = "10{54}1";
//11000011,两端短中间长
String z3 = "1{1,5}0{45,54}1{1,5}";
String z4 = "0{1,5}1{45,54}0{1,5}";
//0000000011100000000,两端长中间短
String z5 = "1{5,}0{1,45}1{5,}";
String z6 = "0{5,}1{1,45}0{5,}";
//01*10
String z7 = "10【0-1】{52}01";
String z8 = "01【0-1】{52}10";

            List<String> zs = new ArrayList<>();  
            zs.add(z1);  
            zs.add(z2);  
            zs.add(z3);  
            zs.add(z4);  
            zs.add(z5);  
            zs.add(z6);  
            zs.add(z7);  
            zs.add(z8);  
            List<Pattern> patterns = new ArrayList<>();  
            for (String z : zs) {  
                Pattern pattern = Pattern.compile(z);  
                patterns.add(pattern);  
            }

解析图片

           BufferedImage bgBI = ImageIO.read(bFile);  

          //获取图片长宽
int minX = bgBI.getMinX();
int maxX = bgBI.getWidth();
int minY = bgBI.getMinY();
int maxY = bgBI.getHeight();
StringBuilder sb = new StringBuilder();
          //对每一个像素二值化处理
for (int Y = minY; Y < maxY; Y++) {
for (int X = minX; X < maxX; X++) {
int rgb = bgBI.getRGB(X, Y);
Color col = new Color(rgb, true);
int r = col.getRed();
int g = col.getGreen();
int b = col.getBlue();
int threshold = (r + g + b) / 3;
          //颜色范围为0-255,取中为阈值

                   if (threshold > 125) {  
                        sb.append(0);  
                    } else {  
                        sb.append(1);  
                    }  
                }  
                for (Pattern p : patterns) {  
                    int index = 0;  
                    Matcher matcher = p.matcher(sb);  
                    boolean find = matcher.find();  
                    if (find) {  
                        index = matcher.start();  
                    }  
                    if (index > 80) {  
                        Integer count = indexMap.get(index);  
                        if (count != null) {  
                            indexMap.put(index, (count + 1));  
                        } else {  
                            indexMap.put(index, 1);  
                        }  
                    }  
                }  

// System.out.println(sb);
sb.delete(0, sb.length());
}

二值化处理后

2、定位

难点为如何告诉计算机阴影位置。

思路------肉眼之所以能判断出阴影位置是因为阴影位置色差小,并且存在边缘线条,所以通过二值化处理后阴影所在区域必然有大量相似数据,且边缘数据相同y(竖着的1或0)

以下面两个正则为例:通过观察发现存在大量以1、0开头结尾长度为56的数据

通过一行一行正则匹配,阴影所在位置x(横)是不变的,只有y(竖)是变化的,累积x的权重,x为横向所以等于偏移量

String z1 = "01{54}0";
String z2 = "10{54}1";
//代码片段,仅讲解,不可直接复制

//计数
Map indexMap = new HashMap<>();

for (Pattern p : patterns) {
int index = 0;
Matcher matcher = p.matcher(sb);
boolean find = matcher.find();
if (find) {
index = matcher.start();
}
if (index > 80) {
Integer count = indexMap.get(index);
if (count != null) {
indexMap.put(index, (count + 1));
} else {
indexMap.put(index, 1);
}
}
}

int k = 0;
int v = 0;
Iterator> iterator = indexMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry next = iterator.next();
if (next.getValue() > v) {
v = next.getValue();
k = next.getKey();
}
}
System.out.println(k);

3、模拟拖拽

//模拟轨迹 
          //获取滑块元素

          WebElement himg= webDriver.findElement(By.xpath(""));

            Actions actions = new Actions(webDriver);  
            actions.clickAndHold(himg);  
            for (int i = 0; i < 10; i++) {  
                actions.moveByOffset(k / 10, 0);  
                Thread.sleep(100);  
            }  
            actions.moveByOffset(40, 0);  
            Thread.sleep(200);  
            actions.moveByOffset(-40, 0);  
            Thread.sleep(200);  

          //这里多出的20是滑块大小需要自行调整
actions.moveByOffset(20, 0);
actions.release(himg).perform();

本地可测试代码

spring boot环境

下载上面的图片,保存到本地进行测试,其它图片可以自己从新定义正则表达式。

联网代码因为每个网站都不一样就不发了,提供思路

1、加载驱动、打开网址

2、点击验证获取背景图片

3、解析图片获取偏移量:主要难点在需要找规律、从而定义正则表达式

4、获取滑块元素,模拟拖拽

@Test
void testimg3() throws IOException {
File bFile = new File("本地图片地址");
//正则
//101,010
String z1 = "0{1}1{54}0";
String z2 = "1{1}0{54}1";
//11000011,两端短中间长
String z3 = "1{1,5}0{45,54}1{1,5}";
String z4 = "0{1,5}1{45,54}0{1,5}";
//0000000011100000000,两端长中间短
String z5 = "1{5,}0{1,45}1{5,}";
String z6 = "0{5,}1{1,45}0{5,}";
//01*10
String z7 = "10【0-1】{52}01";
String z8 = "01【0-1】{52}10";

List<String> zs = new ArrayList<>();  
zs.add(z1);  
zs.add(z2);  
zs.add(z3);  
zs.add(z4);  
zs.add(z5);  
zs.add(z6);  
zs.add(z7);  
zs.add(z8);  

List<Pattern> patterns = new ArrayList<>();  
for (String z : zs) {  
    Pattern pattern = Pattern.compile(z);  
    patterns.add(pattern);  
}  

//计数  
Map<Integer, Integer> indexMap = new HashMap<>();  
//解析图片  
BufferedImage bgBI = ImageIO.read(bFile);  
int minX = bgBI.getMinX();  
int maxX = bgBI.getWidth();  
int minY = bgBI.getMinY();  
int maxY = bgBI.getHeight();  
StringBuilder sb = new StringBuilder();  
for (int Y = minY; Y < maxY; Y++) {  
    for (int X = minX; X < maxX; X++) {  
        int rgb = bgBI.getRGB(X, Y);  
        Color col = new Color(rgb, true);  
        int r = col.getRed();  
        int g = col.getGreen();  
        int b = col.getBlue();  
        //像素平均值  
        int threshold = (r + g + b) / 3;  
        //颜色范围0-255,取中为阈值进行二值化  
        if (threshold > 125) {  
            sb.append(0);  
        } else {  
            sb.append(1);  
        }  
    }  
    //进行正则匹配累计权重  
    for (Pattern p : patterns) {  
        int index = 0;  
        Matcher matcher = p.matcher(sb);  
        boolean find = matcher.find();  
        if (find) {  
            index = matcher.start();  
        }  
        //80为滑块大小、排除滑块  
        if (index > 80) {  
            Integer count = indexMap.get(index);  
            if (count != null) {  
                indexMap.put(index, (count + 1));  
            } else {  
                indexMap.put(index, 1);  
            }  
        }  
    }  
    //输出一行图片像素,复制控制台输出数据到文本,缩小文本观察规律  
    System.out.println(sb);  
    sb.delete(0, sb.length());  
}  
int k = 0;  
int v = 0;  
Iterator<Map.Entry<Integer, Integer>> iterator = indexMap.entrySet().iterator();  
while (iterator.hasNext()) {  
    Map.Entry<Integer, Integer> next = iterator.next();  
    if (next.getValue() > v) {  
        v = next.getValue();  
        k = next.getKey();  
    }  
}  
//偏移量,可用qq截图判断阴影边缘到左侧边缘距离是否准确  
System.out.println(k);  

}