关于滑动验证码的解决方法,网上已经有很多详细的描述了,但是绝大多数都是用的python,这边就扩充一下java,但是验证准确率不是100%,只是强调一下在解决中可能会出现的问题。

注意点

元素截取

  • 元素截图时,尽可能不要通过截取整个屏幕,然后截图子图的方式来截取验证码,这样会因为显示分辨率导致位置偏差存在,无法获取验证码的准确位置,可参考 https://blog.csdn.net/weixin_44578172/article/details/111387534
  • java中直接调用元素的getScreenshotAs即可,但需要选择合理的标签,否侧在执行js代码后会出现图片位移少量的问题。我这边就是选择的最外侧的div标签来进行保存的,而且选择的是先保存无缺口的验证码,然后通过js代码恢复后,再保存具有缺口的验证码

缺口判断

  • 扫描两张图片的起始位置会对缺口的判断有影响,可通过坐标尺或微信截图的方式,确定出方块的初始位置在哪里,即下面代码中getGap方法中的pos变量
  • 验证码缺口判断时,需注意RGB判断阈值,有些验证码中会有些虚假的阴影,并不是我们所要确定的验证码位置,因此,对于阈值的选择也十分重要,这会提高验证精度,即下面代码中equalPixel方法中的threshold

滑块移动

  • 滑块在移动的过程中不要一直加速,因为实际人在操作中,最后一点会稍微减点速的,在计算滑块运动轨迹的时候,最后一个位移距离很有可能会造成滑块超出缺口边界,因此,需要强制对最后一个位移距离进行修改,避免该情况发生,详情见trace方法,滑块的移动尽可能真实的模仿人为操作,来提高准确率
  • 滑块在移动时会有卡顿感,这是因为selenium中默认中的moveByOffset是有200ms的等待时间的,因此,我们可以根据源码重写该方法,使其等待时间为0ms,见moveWithouWait方法
  • 滑块的边界与验证码的边界具有一定的距离,需要将这个距离给考虑进来,可根据一定的测试或测量来选择合适的值,即main方法中的left-=7
  • 移动滑块的时候,一定要注意最后给释放掉

下面代码在实际中会出现验证码回拉的情况,但是这也是提高准确率的一种方式,但是目前来看,这种方法在理论上会出现无解的情况,即一直反复的拉来拉去。但在测试时,还并未出现该情况,但后续需要考虑优化。

/*** Description: 实现滑动验证码的验证* @date:2021/03/30 09:23* @author: lyf*/
public class SildeCode {private WebDriver driver;private Actions actions;private WebElement element;private JavascriptExecutor js;private BufferedImage imgBefore;  // 带有缺口的验证码private BufferedImage imgAfter;  // 不带有缺口的验证码/*** 初始化操作*/public void init() {driver = new ChromeDriver();driver.manage().window().maximize();driver.get("http://www.geetest.com/Register");js = (JavascriptExecutor) driver;js.executeScript("window.scrollTo(1,100)");actions = new Actions(driver);}/*** Selenium方法等待元素出现* @param driver 驱动* @param by     元素定位方式* @return 元素控件*/public static WebElement WaitMostSeconds(WebDriver driver, By by) {try {WebDriverWait AppiumDriverWait = new WebDriverWait(driver, 5);return (WebElement) AppiumDriverWait.until(ExpectedConditions.presenceOfElementLocated(by));} catch (Exception e) {e.printStackTrace();}throw new NoSuchElementException("元素控件未出现");}/*** 保存截图的方法* @param screen 元素截图* @param name   截图保存名字*/public void savePng(File screen, String name) {String screenShortName = name + ".png";try {System.out.println("save screenshot");FileUtils.copyFile(screen, new File(screenShortName));} catch (IOException e) {System.out.println("save screenshot fail");e.printStackTrace();} finally {System.out.println("save screenshot finish");}}/*** 获取无缺口的验证码和带有缺口的验证码*/public void saveCode() {// 获取无缺口的截图js.executeScript("document.querySelectorAll('canvas')[2].style=''");element = WaitMostSeconds(driver, By.cssSelector("div.geetest_window"));File screen = element.getScreenshotAs(OutputType.FILE); //执行屏幕截取savePng(screen, "无缺口");// 获取有缺口的截图js.executeScript("document.querySelectorAll('canvas')[2].classList=[]");element = WaitMostSeconds(driver, By.cssSelector("div.geetest_window"));screen = element.getScreenshotAs(OutputType.FILE); //执行屏幕截取savePng(screen, "有缺口");}/*** 比较两张截图上的当前像素点的RGB值是否相同* 只要满足一定误差阈值,便可认为这两个像素点是相同的** @param x 像素点的x坐标* @param y 像素点的y坐标* @return true/false*/public boolean equalPixel(int x, int y) {int rgbaBefore = imgBefore.getRGB(x, y);int rgbaAfter = imgAfter.getRGB(x, y);// 转化成RGB集合Color colBefore = new Color(rgbaBefore, true);Color colAfter = new Color(rgbaAfter, true);int threshold = 80;   // RGB差值阈值if (Math.abs(colBefore.getRed() - colAfter.getRed()) < threshold &&Math.abs(colBefore.getGreen() - colAfter.getGreen()) < threshold &&Math.abs(colBefore.getBlue() - colAfter.getBlue()) < threshold) {return true;}return false;}/*** 比较两张截图,找出有缺口的验证码截图中缺口所在位置* 由于滑块是x轴方向位移,因此只需要x轴的坐标即可** @return 缺口起始点x坐标* @throws Exception*/public int getGap() throws Exception {imgBefore = ImageIO.read(new File("有缺口.png"));imgAfter = ImageIO.read(new File("无缺口.png"));int width = imgBefore.getWidth();int height = imgBefore.getHeight();int pos = 60;  // 小方块的固定起始位置// 横向扫描for (int i = pos; i < width; i++) {for (int j = 0; j < height; j++) {if (!equalPixel(i, j)) {pos = i;return pos;}}}throw new Exception("未找到滑块缺口");}/*** 计算滑块到达目标点的运行轨迹* 先加速,后减速* @param distance 目标距离* @return 运动轨迹*/public List<Integer> trace(int distance) {java.util.List<Integer> moveTrace = new ArrayList<>();int current = 0;  // 当前位移int threshold = distance * 3 / 5; // 减速阈值double t = 0.2;   // 计算间隔double v = 0.0;     // 初速度double a;     // 加速度while (current < distance) {if (current < threshold) {a = 2;} else {a = -4;}// 位移计算公式double tmp = v;// 移动速度,会出现负值的情况,然后往反方向拉取v = tmp + a * t;int move = (int) (tmp * t + 0.5 * a * t * t);current += move;moveTrace.add(move);}// 考虑到最后一次会超出移动距离,将其强制修改回来,不允许超出int length = moveTrace.size();moveTrace.set(length - 1, moveTrace.get(length - 1) + (current > distance ? -(current - distance) : 0));return moveTrace;}/*** 消除selenium中移动操作的卡顿感* 这种卡顿感是因为selenium中自带的moveByOffset是默认有200ms的延时的* 可参考:https://blog.csdn.net/fx9590/article/details/113096513** @param x x轴方向位移距离* @param y y轴方向位移距离*/public void moveWithoutWait(int x, int y) {PointerInput defaultMouse = new PointerInput(MOUSE, "default mouse");actions.tick(defaultMouse.createPointerMove(Duration.ofMillis(0), PointerInput.Origin.pointer(), x, y)).perform();}/*** 移动滑块,实现验证* @param moveTrace 滑块的运动轨迹* @throws Exception*/public void move(List<Integer> moveTrace) throws Exception {// 获取滑块对象element = WaitMostSeconds(driver, By.cssSelector("div.geetest_slider_button"));// 按下滑块actions.clickAndHold(element).perform();Iterator it = moveTrace.iterator();while (it.hasNext()) {// 位移一次int dis = (int) it.next();moveWithoutWait(dis, 0);}// 模拟人的操作,超过区域moveWithoutWait(5, 0);moveWithoutWait(-3, 0);moveWithoutWait(-2, 0);// 释放滑块actions.release().perform();Thread.sleep(500);}/*** 调出验证码时的一些准备工作* @throws Exception*/public void prepare() throws Exception {// 调出验证码element = WaitMostSeconds(driver, By.cssSelector("div.phone > input"));element.clear();element.sendKeys("12345678910");element = WaitMostSeconds(driver, By.cssSelector("div.sendCode"));element.click();// 等待验证码出现element = WaitMostSeconds(driver, By.cssSelector("a.geetest_close"));Thread.sleep(500);// 保存验证码saveCode();}public static void main(String[] args) throws Exception {SildeCode sc = new SildeCode();sc.init();sc.prepare();int left = sc.getGap();// 验证码的边界差值left -= 7;List<Integer> moveTrace = sc.trace(left);sc.move(moveTrace);}}

好好学习,天天向上

滑动验证码处理 java实现相关推荐

  1. java实现滑动验证码

    功能:java实现滑动验证码 项目是采用springboot,maven 开发工具:采用idea 1.效果演示: 2.后端代码: 控制层: @Controller public class Slide ...

  2. Java添加一个滑动验证码,有啥可难的,分分钟加一个

    滑动验证一般和短信验证码是成对出现,为了避免短信被刷的情况,滑动验证码是一个必须添加的一个功能,下面给大家介绍通过java添加滑动验证的方法. 如何使在电脑端使用的滑动验证,需要引入一段js资源,这里 ...

  3. java 滑块验证码 开源,Java AWT生成滑动验证码

    最近工作需要在登录时使用滑动验证码做登录校验,在生成验证码图片的时候碰到了不小的麻烦 : (. 网上能查到的做法基本上都是使用一张已存在的实际图片作为滑块的图形模板,然后按照此模板做二重循环逐像素地从 ...

  4. 使用java + selenium + OpenCV破解网易易盾滑动验证码

    使用java + selenium + OpenCV破解网易易盾滑动验证码 网易易盾:dun.163.com * 验证码地址:https://dun.163.com/trial/jigsaw * 使用 ...

  5. 一步步实现滑动验证码(拼图验证码),Java图片处理关键代码

    最近滑动验证码在很多网站逐步流行起来,一方面对用户体验来说,比较新颖,操作简单,另一方面相对图形验证码来说,安全性并没有很大的降低.当然到目前为止,没有绝对的安全验证,只是不断增加攻击者的绕过成本. ...

  6. java验证码图片滑动验证码_图片滑动验证码的生成

    使用Java生成图片滑动验证码 image.png 目前接到了一个新的小需求,要在登录时进行滑动图片验证. 搜了一下网上的demo,没有太多很完整的demo.就参考各种文档自己拼凑了一个出来.整理一下 ...

  7. Java滑动验证码【前端部分】

    Java滑动验证码[前端] 实现思路 1.请求后端获得背景图.滑块.x.y.误差范围bound 2.将滑块设置到对应的位置:top = y 3.添加鼠标滑动事件 实现代码 后端请求(Controlle ...

  8. Java图片滑动验证码

    目录 一.配置文件 二.图片 三.代码实现 前后端代码: java滚动验证码-前端和后端完整版_outdata的博客-CSDN博客_java图片滚动验证 图形滑动验证码JAVA实现[前后端结合]_Le ...

  9. java多层if else嵌套语句的优化思路,滑动验证码防刷功能开发

    阿里巴巴java开发手册里面,在控制语句部分有一个推荐,如下: [推荐]表达异常的分支时,少用 if-else 方式,这种方式可以改写成: if (condition) { ...return obj ...

最新文章

  1. mac下vi语法高亮
  2. mysql session大小写_mysql的大小写敏感性
  3. 前15天mysql_Mysql查询今天/昨天/15天前/上个月/去年/上周每日等函数
  4. JavaScript调用服务器事件
  5. css编写的技巧效果总结
  6. 复合辛普森求积公式原理_辛普森法则:公式及其原理
  7. clang 反汇编
  8. win10python3.6.3安装_Win10Python3.6安装impyla
  9. C++编程学到什么程度可以面试工作?
  10. 【每日算法Day 103】老题新做,几乎不会有人想到的解法,它来了
  11. 安装Eclipse的中文语言包
  12. java 解析ttf字体文件_stb_truetype解析ttf字体并将其保存到图片中
  13. Android聊天软件开发(基于网易云IM即时通讯)——发送视频消息(六)
  14. linux亮度调节指令,Linux Mint 亮度调节——xrandr命令学习
  15. java 微信隐藏右上角_不懂这11个隐藏技巧,别说你会用微信
  16. git Incorrect username or password (access token)问题解决
  17. 【Unity】Unity中的异步编程技术详解
  18. ogr2ogr矢量数据要素格式转换
  19. python下载文件损坏_四种方法 恢复损坏的Excel文档
  20. Moving stones

热门文章

  1. PyQt5 技术篇-调用输入对话框(QInputDialog)获取用户输入内容。
  2. PerformanceCounter 简介
  3. 有趣的博娱乐APP合集
  4. mask-rcnn训练识别纸箱模型
  5. 手机必备epub阅读软件
  6. 关于启动eclipse报return code=1的错误的问题解决
  7. 读《春秋》有感之一:士会让贤
  8. java matcher遍历_java正则表达式之Pattern与Matcher类详解
  9. Switch支持的几种类型
  10. Caffeine使用分享