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有不足之处,请大神多多指教,谢谢

转载于:https://www.cnblogs.com/fuhui-study-footprint/p/10289045.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值