• selenium破解极验验证


      啰嗦一下,我使用这个的原因,我的房子到期了,想在官网上租赁一套公租房,因为房源紧张所以要不停的刷页面,而且还有极验的验证码,搞得很烦,效率也低,之后我就想写一段程序,用来自动刷新页面,如果有房子就给我发邮件。

      我遇到的第一个难题,就是页面有极验验证,所以我就搜索了几个破解极验验证的代码,自己尝试。

      原文链接:https://blog.csdn.net/qq_28379809/article/details/81210761

      首先,要想运行程序,需要一个chromedriver.exe文件,有需要可以从我的百度云盘上下载

        链接:https://pan.baidu.com/s/1scnppvHSjd02VrJkDQdNNQ
        提取码:ewyx
      其次:我再部署maven项目的时候遇到org.mail不能使用,之后我是下载了jar包构建了才可以的,这里附上jar包

        链接:https://pan.baidu.com/s/1Mi9oNNRD_2tW-F47KZGqXg 

        提取码:58jp 

      最后我们可以开始讲解代码了

      想了解selenium是什么的朋友,可以请转百度。

      第一步

        导入Maven依赖,javax.mail可以在上文直接下载jar包

    <dependency>
          <groupId>org.seleniumhq.selenium</groupId>
          <artifactId>selenium-server</artifactId>
          <version>3.0.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
        <dependency>
          <groupId>org.jsoup</groupId>
          <artifactId>jsoup</artifactId>
          <version>1.7.2</version>
        </dependency>
    
        <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
        <dependency>
          <groupId>commons-io</groupId>
          <artifactId>commons-io</artifactId>
          <version>2.4</version>
        </dependency>

      第二步:

        声明常量,包括url,图片名称,北京图片名称,和图片存储路径等,并且使用静态块,获取谷歌驱动

       private static String basePath = "src/main/resources/";
        private static String FULL_IMAGE_NAME = "full-image";
        private static String BG_IMAGE_NAME = "bg-image";
        private static int[][] moveArray;// = new int[52][2];
        private static boolean moveArrayInit = false;
        private static int pieceNumber = 0; // 小图片数量
        private static String INDEX_URL = "http://117.71.57.99:9080/online/roomResource.xp?action=showResource";//测试网站登录验证码
        private static WebDriver driver;

      static {
      System.setProperty("webdriver.chrome.driver", "D://git//selenium-geetest-crack//src//file//chromedriver.exe"); // chromedriver.exe的存放路径
       driver = new ChromeDriver();
      }

       第三步:

        先写个main函数,在其中调用iinvoke()方法

        注意 selenum有多种定位元素位置的方法,具体可参考以下两篇文章:https://www.cnblogs.com/csj2018/p/9194618.html  && https://www.cnblogs.com/111testing/p/8100289.html

    private static void invoke() throws IOException, RuntimeException, InterruptedException, StaleElementReferenceException{
            //设置input参数
            driver.get(INDEX_URL);
    
            Thread.sleep(3000);// 为防止页面加载验证码缓慢,获取不到验证按钮,特地增加,如果浏览器加载速度较快,可以删除
            By moveBtn = By.cssSelector(".gt_slider_knob.gt_show");//根据class获取滑动验证按钮
            waitForLoad(driver, moveBtn);//等待加载元素
            WebElement moveElemet = driver.findElement(moveBtn);//定位元素位置
            int i = 0;
            while (i++ < 8) {
                int distance = getMoveDistance(driver);// 获取图片偏移量
                move(driver, moveElemet, distance - 6);// 移动按钮
    
                // 移动之后,无论结果如何,会出现下面两个class为gt_info_type和gt_info_content的标签,注意:如果没有移动是获取不到的
                By gtTypeBy = By.cssSelector(".gt_info_type");//验证结果类型
                By gtInfoBy = By.cssSelector(".gt_info_content");//验证结果内容
                waitForLoad(driver, gtTypeBy);
                String gtType = driver.findElement(gtTypeBy).getText();
                waitForLoad(driver, gtInfoBy);
                String gtInfo = driver.findElement(gtInfoBy).getText();//StaleElementReferenceException
                //System.out.println(gtType + "---" + gtInfo);
                if(gtType.contains("验证通过")){
                    // 获取页面源代码
                    String source = driver.getPageSource();
    
                    // 原页面返回roomColor在后面拼接状态,状态为04则表示没有房子,状态为02则表示有房子
                    if (source.contains("class="roomColor02"")){
                        isRoomText = "有房子啦";
                        SendEmail.sendTextEmail(); // 发送邮件,有需要的话,可以将得到的信息解析出来,一并发送出去
                    }else{
                        isRoomText = "还没有房子";
                    }
                    System.out.println(isRoomText);
                }
                /**
                 * 再来一次:
                 * 验证失败:
                 */
                if (!gtType.equals("再来一次:") && !gtType.equals("验证失败:")) {
                    Thread.sleep(2000);
                    //System.out.println(driver);
                    break;
                }
                Thread.sleep(2000);
            }
        }

    第四步:

      计算出具体的偏移量

    /**
         * 计算需要平移的距离
         *
         * @param driver
         * @return
         * @throws IOException
         */
        public static int getMoveDistance(WebDriver driver) throws IOException , RuntimeException{
            String pageSource = driver.getPageSource(); // 获取网页源代码
            // 获取元素图片路径 以及 获取原始带背景图片路径
            String fullImageUrl = getFullImageUrl(pageSource);
            String getBgImageUrl = getBgImageUrl(pageSource);
    
            // 将两张图片拷贝到本机地址
            FileUtils.copyURLToFile(new URL(fullImageUrl), new File(basePath + FULL_IMAGE_NAME + ".jpg"));
            FileUtils.copyURLToFile(new URL(getBgImageUrl), new File(basePath + BG_IMAGE_NAME + ".jpg"));
            // 获取已经错位的图片地址
            initMoveArray(driver);
    
            // 拼接融合图片
            restoreImage(FULL_IMAGE_NAME);
            restoreImage(BG_IMAGE_NAME);
    
            // 根据两张图片计算出偏移的位置
            BufferedImage fullBI = ImageIO.read(new File(basePath + "result/" + FULL_IMAGE_NAME + "result3.jpg"));
            BufferedImage bgBI = ImageIO.read(new File(basePath + "result/" + BG_IMAGE_NAME + "result3.jpg"));
            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;
                    }
                }
            }
            throw new RuntimeException("未找到需要平移的位置");
        }
    
        /**
         * 获取原始图url
         *
         * @param pageSource
         * @return
         */
        private static String getFullImageUrl(String pageSource) {
            String url = null;
            Document document = Jsoup.parse(pageSource);
            String style = document.select("[class=gt_cut_fullbg_slice]").first().attr("style");
            Pattern pattern = Pattern.compile("url\("(.*)"\)");
            Matcher matcher = pattern.matcher(style);
            if (matcher.find()) {
                url = matcher.group(1);
            }
            url = url.replace(".webp", ".jpg");
            //System.out.println(url);
            return url;
        }
    
        /**
         * 获取带背景的url
         *
         * @param pageSource
         * @return
         */
        private static String getBgImageUrl(String pageSource) {
            String url = null;
            Document document = Jsoup.parse(pageSource);
            String style = document.select(".gt_cut_bg_slice").first().attr("style");
            Pattern pattern = Pattern.compile("url\("(.*)"\)");
            Matcher matcher = pattern.matcher(style);
            if (matcher.find()) {
                url = matcher.group(1);
            }
            url = url.replace(".webp", ".jpg");
            //System.out.println(url);
            return url;
        }
        
        /**
         * 获取move数组
         *
         * @param driver
         */
        private static void initMoveArray(WebDriver driver) {
            if (moveArrayInit) {
                return;
            }
            Document document = Jsoup.parse(driver.getPageSource());
            Elements elements = document.select("[class=gt_cut_bg gt_show]").first().children(); // 获取底图错位后的图片元素们
            int i = 0;
            pieceNumber = elements.size();
            moveArray = new int[pieceNumber][2];
            for (Element element : elements) {
                Pattern pattern = Pattern.compile(".*background-position: (.*?)px (.*?)px.*");
                Matcher matcher = pattern.matcher(element.toString());
                if (matcher.find()) {
                    String width = matcher.group(1);
                    String height = matcher.group(2);
                    moveArray[i][0] = Integer.parseInt(width);
                    moveArray[i++][1] = Integer.parseInt(height);
                } else {
                    throw new RuntimeException("解析异常");
                }
            }
            moveArrayInit = true;
        }
    
        /**
         * 还原图片
         *
         * @param type
         */
        private static void restoreImage(String type) throws IOException {
            //把图片裁剪为2 * 26份
            for (int i = 0; i < pieceNumber; i++) {
                cutPic(basePath + type + ".jpg"
                        , basePath + "result/" + type + i + ".jpg", -moveArray[i][0], -moveArray[i][1], 10, 58);
            }
            //拼接图片
            String[] b = new String[(int)pieceNumber/2];
            for (int i = 0; i < (int)pieceNumber/2; i++) {
                b[i] = String.format(basePath + "result/" + type + "%d.jpg", i);
            }
            mergeImage(b, 1, basePath + "result/" + type + "result1.jpg");
            //拼接图片
            String[] c = new String[(int)pieceNumber/2];
            for (int i = 0; i < (int)pieceNumber/2; i++) {
                c[i] = String.format(basePath + "result/" + type + "%d.jpg", i + (int)pieceNumber/2);
            }
            mergeImage(c, 1, basePath + "result/" + type + "result2.jpg");
            mergeImage(new String[]{basePath + "result/" + type + "result1.jpg",
                    basePath + "result/" + type + "result2.jpg"}, 2, basePath + "result/" + type + "result3.jpg");
            //删除产生的中间图片
            for (int i = 0; i < pieceNumber; i++) {
                new File(basePath + "result/" + type + i + ".jpg").deleteOnExit();
            }
            new File(basePath + "result/" + type + "result1.jpg").deleteOnExit();
            new File(basePath + "result/" + type + "result2.jpg").deleteOnExit();
        }
    
        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]);
        }

      第五步;

        拖住验证按钮,并根据偏移量移动位置,此处因为原移动公式,对我的验证码成功率不高,所以我自己改进了一下

        此处可根据自己要操作的验证码界面自己调试

        该函数中,包含selenium对鼠标的操作,详情可参考:https://www.cnblogs.com/lingling99/p/5750266.html

    /**
         * 移动
         *
         * @param driver
         * @param element
         * @param distance
         * @throws InterruptedException
         */
        public static void move(WebDriver driver, WebElement element, int distance) throws InterruptedException {
            int xDis = distance;// 偏移量
            int moveX = new Random().nextInt(5) - 2;//生成随机数
            int moveY = 1;
            Actions actions = new Actions(driver);
            new Actions(driver).clickAndHold(element).perform();//单击拖住按钮
            Thread.sleep(1000);//slow down
            // 偏移量
            int offset  = (xDis+moveX)/2;
            actions.moveByOffset(offset,moveY).perform();// 第一次偏移
            Thread.sleep((int)(Math.random()*1000));
            actions.moveByOffset(distance-offset-moveX,moveY).perform();//第二次偏移
            Thread.sleep(500);
            actions.release(element).perform();// 释放按钮
        }

      最后,发送邮件那块,可以参考我之前写的文章进行操作,用不着ical4j可以删除,下方是连接,该篇文章底部有java email发送邮件时出现的问题总结,希望对大家有所帮助

        https://www.cnblogs.com/fuhui-study-footprint/p/8464968.html

      此处用于笔记,第一次使用selenium有不足之处,请大神多多指教,谢谢

  • 相关阅读:
    java接入钉钉机器人(带源码)
    使用java做一个能赚钱的微信群聊机器人(2020年基于PC端协议最新可用版)
    侠说java8--Stream流操作学习笔记,都在这里了
    Elasticsearch调优篇-慢查询分析笔记
    网络探测和抓包工具 wireshark
    window10远程ubuntu18.04
    springdataJPA mysql myisam innodb
    命令集
    java tmpdir 启动 kafka 命令行
    java jar 启动命令
  • 原文地址:https://www.cnblogs.com/fuhui-study-footprint/p/10289045.html
Copyright © 2020-2023  润新知