【验证码识别】OpenCV挑战极验滑动拼图验证码

时间:2025-02-07 10:46:22
private final String INDEX_URL = "/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[3]; bgRgb[0] = (bgBI.getRGB(i, j) & 0xff0000) >> 16; bgRgb[1] = (bgBI.getRGB(i, j) & 0xff00) >> 8; bgRgb[2] = (bgBI.getRGB(i, j) & 0xff); if (difference(fullRgb, bgRgb) > 255) { return i; } } } } catch (Exception e) { return 0; } finally { fullFile.delete(); bgFile.delete(); } return 0; } private static int difference(int[] a, int[] b) { return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]) + Math.abs(a[2] - b[2]); } /** * // 执行 JS 代码并生成图片 * * @param driver * @param jsString * @param input * @return图片路径 */ public static String getImgByJs(WebDriver driver, String jsString) { try { String imgFilePath = "c://GeeTest_" + System.currentTimeMillis() + "_" + (Math.random() * 9 + 1) * 100000 + ".jpg"; String imgInfo = ((JavascriptExecutor) driver).executeScript(jsString).toString(); if (imgInfo != null && imgInfo.contains("data")) { imgInfo = imgInfo.substring(imgInfo.indexOf(",") + 1); ByteArrayOutputStream outputStream = imgStrToFile(imgInfo); if (outputStream != null) { byte[] picBytes = outputStream.toByteArray(); outPicToFile(picBytes, imgFilePath); return imgFilePath; } } return null; } catch (Exception e) { return null; } } /** * 将base64字节码转byte输出流 * * @param imgBase64Str * @return */ private static ByteArrayOutputStream imgStrToFile(String imgBase64Str) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); try { if (imgBase64Str != null) { BASE64Decoder decoder = new BASE64Decoder(); byte[] data = decoder.decodeBuffer(imgBase64Str); outputStream.write(data); outputStream.flush(); } return outputStream; } catch (Exception e) { return null; } } /** * 图片流转图片 * * @param o * @param imgFilePath */ private static void outPicToFile(Object o, String imgFilePath) { if (o == null) return; try { if (o instanceof byte[]) { // 转为图片 if (((byte[]) o).length == 0) return; File imgFile = new File(imgFilePath); // byte数组到图片 FileImageOutputStream imageOutput = new FileImageOutputStream(imgFile); imageOutput.write((byte[]) o, 0, ((byte[]) o).length); imageOutput.close(); } else { return; } } catch (Exception e) { } } /** * 模拟人工移动 * * @param driver * @param element页面滑块 * @param distance需要移动距离 * @throws InterruptedException */ 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 = 1; 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 distance需要移动的距离 * @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; } private void seleniumTest() { ChromeDriverManager manager = ChromeDriverManager.getInstance(); int status = -1; String phone = "13814389438"; try { WebDriver driver = manager.getDriver(); driver.get(INDEX_URL); driver.manage().window().maximize(); // 设置浏览器窗口最大化 Thread.sleep(2000); // 输入手机号 WebElement phoneElemet = waitWebElement(driver, By.xpath("//input[@placeholder='手机号码']"), 20); phoneElemet.clear(); for (int i = 0; i < phone.length(); i++) { char c = phone.charAt(i); phoneElemet.sendKeys(c + ""); phoneElemet.click(); } sleep(50); // 点击获取验证码 waitWebElement(driver, By.className("sendCode"), 20).click(); sleep(2000); // 完整背景图geetest_canvas_fullbg geetest_fade geetest_absolute String fullImgJs = "return (\"geetest_canvas_fullbg geetest_fade geetest_absolute\")[0].toDataURL(\"image/png\");"; String fullImgPath = getImgByJs(driver, fullImgJs); // 含有缺口背景图geetest_canvas_bg geetest_absolute String bgImgJs = "return (\"geetest_canvas_bg geetest_absolute\")[0].toDataURL(\"image/png\");"; String bgImgPath = getImgByJs(driver, bgImgJs); // 获取滑动按钮 WebElement moveElemet = waitWebElement(driver, By.className("geetest_slider_button"), 20); // 获取滑动距离并删除图片 int distance = getMoveDistance(driver, fullImgPath, bgImgPath); if (distance == 0) { } // 滑动 move(driver, moveElemet, distance - 6); // 滑动结果 sleep(2 * 1000); String gtInfo = waitWebElement(driver, By.className("sendCode"), 20).getAttribute("innerHTML"); System.out.println(gtInfo); } catch (Exception e) { e.printStackTrace(); } finally { manager.closeDriver(status); } } protected static void sleep(long time) { try { Thread.sleep(time); } catch (InterruptedException e) { } }