一丶解析驗證碼組成
從上面三張圖來看,極驗滑動拼圖驗證碼是由一個小的拼圖和一個大的背景圖組成,拼圖的形狀各式各樣,背景圖中有一個陰影缺口,與拼圖形狀一致。
這里我們使用F12大法打開瀏覽器控制台,觀察一下驗證碼的頁面結構。
通過觀察可以看到,驗證碼所包含的圖片均以<canves>
畫布的形式呈現在頁面中,且有三張圖片,且第三張圖片被加上了屬性style=“display: none;”,即為隱藏不顯示。那么我們修改下頁面代碼,看下這張圖究竟是什么。
修改完代碼發現,這不就是完整的背景圖嘛。那么根據上面的命名來看,基本可以確定這三張圖分別是什么了。
-
第一張class為geetest_canvas_bg geetest_absolute,可以確定為帶缺口的背景圖。
-
第二張class為geetest_canvas_slice geetest_absolute,可以確定為拼圖。
-
第三張便是完整的圖片。
二丶分析出破解思路
- 首先根據這個驗證碼的組成,來分析一下我們人要做的事情:
按照正常的手動操作流程來看,我們需要看出背景圖中與拼圖對應的陰影缺口的位置,然后鼠標按住下方滑塊來把拼圖對正到缺口位置來完成驗證。
- 然后根據人要做的事情,來分析一下程序要做的事情:
根據分析得出下面幾個步驟:
1.獲取到兩張圖片(帶缺口背景圖、完整背景圖)
2.處理圖片,得到陰影位置並計算滑動距離
3.根據滑動距離模擬滑動
三丶具體操作步驟
1丶獲取到兩張圖片
由於這里的圖片都是通過canvas
畫布呈現的,我們可以通過執行js代碼來生成圖片。
可以參考《如何抓取canvas畫布中的圖片》。
2丶處理圖片,計算滑動距離
通過第一步得到的兩張圖片可以看出,兩張圖有兩處不同的地方,一處差異不大,一處差異較大,我們可以通過比較每一個像素點的差異度來確定陰影缺口的位置。缺口的位置橫坐標減去小圖距離邊框的距離即為滑動距離。
以下是關鍵部分代碼:
private final String INDEX_URL = "https://www.geetest.com/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[