selenium(java)實現(xiàn)滑動圖片驗證碼

一、原由

網(wǎng)上搜索了一下,有一些使用selenium實現(xiàn)滑動圖片的代碼,但是多是需要獲取完整圖的?,F(xiàn)在很多滑動圖片驗證碼沒有完整圖,這里記錄一下我實現(xiàn)的。

二、整理思路

1、獲取背景圖(bgImg)、獲取驗證圖(vrImg)

2、對背景圖與驗證圖做二值化處理(PS:這里二值化的閾值需要調(diào)整,不然可能獲取不到想要的效果)

3、比較背景圖與驗證碼圖相似的地方(二值化之后背景圖就會有跟驗證圖一樣的圖形),校驗白邊緣——一個節(jié)點的四周節(jié)點相同,則相似度加一,獲取相似度最大的x軸數(shù)據(jù),及是我們需要知道的拖動距離

4、使用selenium實現(xiàn)拖動

三、代碼實現(xiàn)

1、獲取圖片以及下載圖片(下載使用httpClient實現(xiàn))

使用webDriver.findElement()方法獲取圖片以及圖片地址

2、圖片二值化代碼

/**

* 對圖片進(jìn)行二值化

* @author <a href="mailto:zhouchao@zhexinit.com" >周超</a>

* @param 原圖

* @param 二值化之后存儲的文件

* @param 是否為背景圖(背景圖與驗證圖處理方式不同)

* @throws IOException

*/

public void binaryImage(File imageFile,File descFile,boolean bgImage) throws IOException{

? ? String fileName=imageFile.getName();

? ? String fileType=imageFile.getName().substring(fileName.lastIndexOf(".")+1);

? ? BufferedImage image = ImageIO.read(imageFile);

? ? int width = image.getWidth();

? ? int height = image.getHeight();

? ? BufferedImage binaryImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);

? ? for(int i= 0 ; i < width ; i++){

? ? ? ? for(int j = 0 ; j < height; j++){

? ? ? ? int rgb=image.getRGB(i, j);

? ? ? ? if(bgImage) {

? ? ? ? ? ? ? rgb=getBgImageRgb(rgb);

? ? ? ? }else {

? ? ? ? ? ? ? rgb = getImageRgb(rgb);

? ? ? ? }

? ? ? ? binaryImage.setRGB(i, j, rgb);

? ? ? ? }

? ? }

? ? ImageIO.write(binaryImage, fileType, descFile);

}

/**

* 如果使用該方法二值化不行,需要調(diào)整參數(shù)r>200&g>200&b>200的參數(shù)

* @author <a href="mailto:zhouchao@zhexinit.com" >周超</a>

* @param i

* @return

*/

? ? private static int getImageRgb(int i) {

? ? ? ? ?String data=Integer.toHexString(i)+"";

? ? ? ? if(data.length()==6) {

? ? ? ? ? ? return 0x00;

? ? ? ? ?}

? ? ? ? int rgb =i& 0xFFFFFF;

? ? ? ? int r=(rgb& 0xff0000) >> 16;

? ? ? ? int g=(rgb& 0xff00) >> 8;

? ? ? ? int b=(rgb& 0xff);

? ? ? ? if(r>200&g>200&b>200) {

? ? ? ? ? ? return 0xFFFFFF;

? ? ? ? }

? ? ? ? return 0x00;

? ? }


? ? /**

? ? * 如果使用該方法二值化不行,需要調(diào)整參數(shù)avg>120&avg<160的參數(shù)

? ? * @author <a href="mailto:zhouchao@zhexinit.com" >周超</a>

? ? * @param i

? ? * @return

? ? */

? ? private static int getBgImageRgb(int i) {

? ? ? ? int rgb =i& 0xFFFFFF;

? ? ? ? int r=(rgb& 0xff0000) >> 16;

? ? ? ? int g=(rgb& 0xff00) >> 8;

? ? ? ? int b=(rgb& 0xff);

? ? ? ? int avg=(r+g+b)/3;

? ? ? ? if(avg>120&avg<160) {

? ? ? ? ? ? return 0xFFFFFF;

? ? ? ? }

? ? ? ? return 0x00;

? ? }

注意:getImageRgb()與getBgImageRgb()可能需要根據(jù)圖片的不同做一些范圍調(diào)整。

二值化的效果如下:

原圖

二值化之后:


這樣二值化之后的圖,我們就可以將問題變?yōu)樵谝粡垐D片中查下另一張圖的位置了


3、比較圖獲取位置

/**

*

* 搜索圖片位子

* @param 二值化之后的背景圖

* @param 二值化之后的校驗圖

* @return

* @throws IOException

*/

public int searchLocation(File bgImgBinaryFile,File verifyBinaryImgFile) throws IOException {

BufferedImage bgImg = ImageIO.read(bgImgBinaryFile);

BufferedImage vrImg = ImageIO.read(verifyBinaryImgFile);

int[][] bgRgb=getImageGRB(bgImg);

int[][] vrRgb=getImageGRB(vrImg);

return searchImage(bgRgb,vrRgb);

}

/**

? ? * 這里非黑即白 值為0或1,1表示白色,0表示黑色

? ? * @param bfImage

? ? * @return

? ? */

? ? public static int[][] getImageGRB(BufferedImage bfImage) {

? ? ? ? int width = bfImage.getWidth();

? ? ? ? int height = bfImage.getHeight();

? ? ? ? int[][] result = new int[height][width];//這里就是y,x才跟圖一樣

? ? ? ? for (int h = 0; h < height; h++) {

? ? ? ? for (int w = 0; w <width ; w++) {

? ? ? ? ? ? ? ? result[h][w] = getZeroOrOne(bfImage.getRGB(w, h));

? ? ? ? ? ? ? ? System.out.print(result[h][w]+" ");

? ? ? ? ? ? }

? ? ? ? System.out.println();

? ? ? ? }

? ? ? ? System.out.println("===================================");

? ? ? ? return result;

? ? }

/**

? ? * 將圖片像素變成0或1,閾值可以根據(jù)實際情況調(diào)整

? ? * @param bfImage

? ? * @return

? ? */

private static int getZeroOrOne(int i) {

? ? int rgb =i& 0xFFFFFF;

? ? int r=(rgb& 0xff0000) >> 16;

? ? int g=(rgb& 0xff00) >> 8;

? ? int b=(rgb& 0xff);

? ? if(r>210&g>210&b>210) {

? ? return 1;

? ? }

? ? return 0x00;

? ? }

/**

? ? * 遍歷圖片,進(jìn)行比較,得出相似度最高的位置

? ? 這里是一個像素一個像素去比較的,具體比較方法為compare(y,x,bgRgb,vrRgb)

? ? * @param bfImage

? ? * @return

? ? */

private static int searchImage(int[][] bgRgb,int[][] vrRgb) {

? ? int bgY=bgRgb.length;

int bgX=bgRgb[0].length;

int vrY=vrRgb.length;

int vrX=vrRgb[0].length;

int xLocation=0;

int yLocation=0;

int maxCount=0;

for(int y=1;y<bgY-vrY-1;y++) {

for(int x=1;x<bgX-vrX-1;x++) {

int count=compare(y,x,bgRgb,vrRgb);

if(count>maxCount) {

maxCount=count;

yLocation=y;

xLocation=x;

}

}

}

LOGGER.info("最佳位置為({},{}),相同數(shù)比例為={}",new Object[] {xLocation,yLocation,maxCount});

? ? return xLocation;

? ? }


/**

? ? * 針對背景圖中的像素位置(Y,X),那驗證圖與原圖做比較

? ? 1、比較邊框,及比較驗證圖中值為1的點

2、爭奪當(dāng)前驗證圖中1的點,比較它四周的節(jié)點,是否相同,相同就相似度加一

PS:其實就是比較框框

? ? * @param bfImage

? ? * @return

? ? */

? ? private static int compare(int bgY,int bgX,int[][] bgRgb,int[][] vrRgb) {

? ? int count=0;

? ? int vrY=vrRgb.length;

int vrX=vrRgb[0].length;

//遍歷小圖節(jié)點

for(int y=0;y<vrY;y++) {

for(int x=0;x<vrX;x++) {

//只對1做比較

if(vrRgb[y][x]!=1){

continue;

}

boolean isRight=true;

//比較當(dāng)前點四周的節(jié)點是否相同

for(int i=-1;i<2;i++) {

for(int j=-1;j<2;j++) {

int tempX=x+i;

int tempY=y+j;

int tempBgY=y+bgY+j;

int tempBgX=x+bgX+i;

if(tempY<0||tempX<0||tempY>vrY-1||tempX>vrX-1) {

continue;

}

if(tempBgY<0||tempBgX<0||tempBgY>bgRgb.length-1||tempBgX>bgRgb[0].length-1) {

continue;

}

if(vrRgb[tempY][tempX]!=bgRgb[tempBgY][tempBgX]) {

isRight=false;

}

}

}

if(isRight) {

count++;

}

}

}

return count;

? ? }

其中g(shù)etImageGRB()方法打印的效果圖類似這樣:(下面是部分截圖)


4、進(jìn)行滑動


/**

? *

? * moveButton:拖動按鈕

? * @param webDriver

? * @param buttonElement? 按鈕

? * @param location? 拖動距離

? * @param stepBean

? * @throws InterruptedException

*/

public void moveButton(WebDriver webDriver,WebElement buttonElement,int location) throws InterruptedException {

? ? int defaultStep=RandomUtils.getRandomNum(20)+20;

? ? int distance=location;

//生成隨機(jī)軌跡模型

? ? List<Integer> stepNumList=new ArrayList<>();

? ? getRandomDistribution(distance,defaultStep,stepNumList);

//點擊數(shù)據(jù)并按住

? ? Actions action = new Actions(webDriver);

? ? action.clickAndHold(buttonElement);

? ? for(Integer num:stepNumList) {

? ? //拖動按鈕

? ? ? ? action.moveByOffset(num,0);

? ? ? ? action.perform();

? ? }

//釋放按鈕

? ? action.release(buttonElement).perform();

}

/**

? *

? * 隨機(jī)軌跡模型

? * @param webDriver

? * @param distance? 拖動距離

? * @param defaultStep? 進(jìn)行拖動的次數(shù)

? * @param dataList 軌跡模型

? * @throws InterruptedException

*/

private static void getRandomDistribution(int distance,int defaultStep,List<Integer> dataList) {

if (defaultStep == 1) {

? ? dataList.add(distance);

return;

}

int item = distance / defaultStep;

item=item+RandomUtils.getRandomIntNum(-item * 2, item * 3);

dataList.add(item);

getRandomDistribution(distance - item, defaultStep - 1,dataList);

}


四、總結(jié)

要實現(xiàn)滑動圖片驗證,關(guān)鍵還是識別需要滑動的位置。通過二值化可以實現(xiàn),這里的二值化,需要根據(jù)滑動的圖片在設(shè)置二值化的閾值。一般滑動圖片都有明顯的特征的,調(diào)整閾值就可以實現(xiàn)。本文僅用于技術(shù)學(xué)習(xí)參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容