selenium破解極驗驗證

  囉嗦一下,我使用這個的緣由,個人房子到期了,想在官網上租賃一套公租房,由於房源緊張因此要不停的刷頁面,並且還有極驗的驗證碼,搞得很煩,效率也低,以後我就想寫一段程序,用來自動刷新頁面,若是有房子就給我發郵件。css

  我遇到的第一個難題,就是頁面有極驗驗證,因此我就搜索了幾個破解極驗驗證的代碼,本身嘗試。html

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

  首先,要想運行程序,須要一個chromedriver.exe文件,有須要能夠從個人百度雲盤上下載git

    連接:https://pan.baidu.com/s/1scnppvHSjd02VrJkDQdNNQ
    提取碼:ewyx
  其次:我再部署maven項目的時候遇到org.mail不能使用,以後我是下載了jar包構建了才能夠的,這裏附上jar包web

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

    提取碼:58jp 數組

  最後咱們能夠開始講解代碼了瀏覽器

  想了解selenium是什麼的朋友,能夠請轉百度。併發

  第一步dom

    導入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有不足之處,請大神多多指教,謝謝

相關文章
相關標籤/搜索