好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

使用java + selenium + OpenCV破解网易易盾滑动验证码的示例

网易易盾:dun.163.com

?

1

2

3

* 验证码地址:https: //dun.163.com/trial/jigsaw

* 使用OpenCv模板匹配

* Java + Selenium + OpenCV

产品样例


接下来就是见证奇迹的时刻!

注意!!!
· 在模拟滑动时不能按照相同速度或者过快的速度滑动,需要向人滑动时一样先快后慢,这样才不容易被识别。
模拟滑动代码↓↓↓

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

/**

      * 模拟人工移动

      * @param driver

      * @param element页面滑块

      * @param distance需要移动距离

      */

     public static void move(WebDriver driver, WebElement element, int distance) throws InterruptedException {

         int randomTime = 0 ;

         if (distance > 90 ) {

             randomTime = 250 ;

         } else if (distance > 80 && distance <= 90 ) {

             randomTime = 150 ;

         }

         List<Integer> track = getMoveTrack(distance - 2 );

         int moveY = 1 ;

         try {

             Actions actions = new Actions(driver);

             actions.clickAndHold(element).perform();

             Thread.sleep( 200 );

             for ( int i = 0 ; i < track.size(); i++) {

                 actions.moveByOffset(track.get(i), moveY).perform();

                 Thread.sleep( new Random().nextInt( 300 ) + randomTime);

             }

             Thread.sleep( 200 );

             actions.release(element).perform();

         } catch (Exception e) {

             e.printStackTrace();

         }

     }

     /**

      * 根据距离获取滑动轨迹

      * @param distance需要移动的距离

      * @return

      */

     public static List<Integer> getMoveTrack( int distance) {

         List<Integer> track = new ArrayList<>(); // 移动轨迹

         Random random = new Random();

         int current = 0 ; // 已经移动的距离

         int mid = ( int ) distance * 4 / 5 ; // 减速阈值

         int a = 0 ;

         int move = 0 ; // 每次循环移动的距离

         while ( true ) {

             a = random.nextInt( 10 );

             if (current <= mid) {

                 move += a; // 不断加速

             } else {

                 move -= a;

             }

             if ((current + move) < distance) {

                 track.add(move);

             } else {

                 track.add(distance - current);

                 break ;

             }

             current += move;

         }

         return track;

     }

 

操作过程

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

/**

      * 获取网易验证滑动距离

      *

      * @return

      */

     public static String dllPath = "C://chrome//opencv_java440.dll" ;

 

     public double getDistance(String bUrl, String sUrl) {

         System.load(dllPath);

         File bFile = new File( "C:/EasyDun_b.png" );

         File sFile = new File( "C:/EasyDun_s.png" );

         try {

             FileUtils.copyURLToFile( new URL(bUrl), bFile);

             FileUtils.copyURLToFile( new URL(sUrl), sFile);

             BufferedImage bgBI = ImageIO.read(bFile);

             BufferedImage sBI = ImageIO.read(sFile);

             // 裁剪

             cropImage(bgBI, sBI, bFile, sFile);

             Mat s_mat = Imgcodecs.imread(sFile.getPath());

             Mat b_mat = Imgcodecs.imread(bFile.getPath());

            

             //阴影部分为黑底时需要转灰度和二值化,为白底时不需要

             // 转灰度图像

             Mat s_newMat = new Mat();

             Imgproc.cvtColor(s_mat, s_newMat, Imgproc.COLOR_BGR2GRAY);

             // 二值化图像

             binaryzation(s_newMat);

             Imgcodecs.imwrite(sFile.getPath(), s_newMat);

 

             int result_rows = b_mat.rows() - s_mat.rows() + 1 ;

             int result_cols = b_mat.cols() - s_mat.cols() + 1 ;

             Mat g_result = new Mat(result_rows, result_cols, CvType.CV_32FC1);

             Imgproc.matchTemplate(b_mat, s_mat, g_result, Imgproc.TM_SQDIFF); // 归一化平方差匹配法TM_SQDIFF 相关系数匹配法TM_CCOEFF

                                                                                

             Core.normalize(g_result, g_result, 0 , 1 , Core.NORM_MINMAX, - 1 , new Mat());

             Point matchLocation = new Point();

             MinMaxLocResult mmlr = Core.minMaxLoc(g_result);

             matchLocation = mmlr.maxLoc; // 此处使用maxLoc还是minLoc取决于使用的匹配算法

             Imgproc.rectangle(b_mat, matchLocation, new Point(matchLocation.x + s_mat.cols(), matchLocation.y + s_mat.rows()), new Scalar( 0 , 255 , 0 , 0 ));

             Imgcodecs.imwrite(bFile.getPath(), b_mat);

             return matchLocation.x + s_mat.cols() - sBI.getWidth() + 12 ;

         } catch (Throwable e) {

             e.printStackTrace();

             return 0 ;

         } finally {

              bFile.delete();

              sFile.delete();

         }

     }

 

     /**

      * 图片亮度调整

      *

      * @param image

      * @param param

      * @throws IOException

      */

     public void bloding(BufferedImage image, int param) throws IOException {

         if (image == null ) {

             return ;

         } else {

             int rgb, R, G, B;

             for ( int i = 0 ; i < image.getWidth(); i++) {

                 for ( int j = 0 ; j < image.getHeight(); j++) {

                     rgb = image.getRGB(i, j);

                     R = ((rgb >> 16 ) & 0xff ) - param;

                     G = ((rgb >> 8 ) & 0xff ) - param;

                     B = (rgb & 0xff ) - param;

                     rgb = ((clamp( 255 ) & 0xff ) << 24 ) | ((clamp(R) & 0xff ) << 16 ) | ((clamp(G) & 0xff ) << 8 ) | ((clamp(B) & 0xff ));

                     image.setRGB(i, j, rgb);

 

                 }

             }

         }

     }

 

     // 判断a,r,g,b值,大于256返回256,小于0则返回0,0到256之间则直接返回原始值

     private int clamp( int rgb) {

         if (rgb > 255 )

             return 255 ;

         if (rgb < 0 )

             return 0 ;

         return rgb;

     }

 

     /**

      * 生成半透明小图并裁剪

      *

      * @param image

      * @return

      */

     private void cropImage(BufferedImage bigImage, BufferedImage smallImage, File bigFile, File smallFile) {

         int y = 0 ;

         int h_ = 0 ;

         try {

             // 2 生成半透明图片

             bloding(bigImage, 75 );

             for ( int w = 0 ; w < smallImage.getWidth(); w++) {

                 for ( int h = smallImage.getHeight() - 2 ; h >= 0 ; h--) {

                     int rgb = smallImage.getRGB(w, h);

                     int A = (rgb & 0xFF000000 ) >>> 24 ;

                     if (A >= 100 ) {

                         rgb = ( 127 << 24 ) | (rgb & 0x00ffffff );

                         smallImage.setRGB(w, h, rgb);

                     }

                 }

             }

             for ( int h = 1 ; h < smallImage.getHeight(); h++) {

                 for ( int w = 1 ; w < smallImage.getWidth(); w++) {

                     int rgb = smallImage.getRGB(w, h);

                     int A = (rgb & 0xFF000000 ) >>> 24 ;

                     if (A > 0 ) {

                         if (y == 0 )

                             y = h;

                         h_ = h - y;

                         break ;

                     }

                 }

             }

             smallImage = smallImage.getSubimage( 0 , y, smallImage.getWidth(), h_);

             bigImage = bigImage.getSubimage( 0 , y, bigImage.getWidth(), h_);

             ImageIO.write(bigImage, "png" , bigFile);

             ImageIO.write(smallImage, "png" , smallFile);

         } catch (Throwable e) {

             System.out.println(e.toString());

         }

     }

 

     /**

      *

      * @param mat

      *   二值化图像

      */

     public static void binaryzation(Mat mat) {

         int BLACK = 0 ;

         int WHITE = 255 ;

         int ucThre = 0 , ucThre_new = 127 ;

         int nBack_count, nData_count;

         int nBack_sum, nData_sum;

         int nValue;

         int i, j;

         int width = mat.width(), height = mat.height();

         // 寻找最佳的阙值

         while (ucThre != ucThre_new) {

             nBack_sum = nData_sum = 0 ;

             nBack_count = nData_count = 0 ;

 

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

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

                     nValue = ( int ) mat.get(j, i)[ 0 ];

 

                     if (nValue > ucThre_new) {

                         nBack_sum += nValue;

                         nBack_count++;

                     } else {

                         nData_sum += nValue;

                         nData_count++;

                     }

                 }

             }

             nBack_sum = nBack_sum / nBack_count;

             nData_sum = nData_sum / nData_count;

             ucThre = ucThre_new;

             ucThre_new = (nBack_sum + nData_sum) / 2 ;

         }

         // 二值化处理

         int nBlack = 0 ;

         int nWhite = 0 ;

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

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

                 nValue = ( int ) mat.get(j, i)[ 0 ];

                 if (nValue > ucThre_new) {

                     mat.put(j, i, WHITE);

                     nWhite++;

                 } else {

                     mat.put(j, i, BLACK);

                     nBlack++;

                 }

             }

         }

         // 确保白底黑字

         if (nBlack > nWhite) {

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

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

                     nValue = ( int ) (mat.get(j, i)[ 0 ]);

                     if (nValue == 0 ) {

                         mat.put(j, i, WHITE);

                     } else {

                         mat.put(j, i, BLACK);

                     }

                 }

             }

         }

     }

     // 延时加载

     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 ;

     }

注意:有一个问题还没有解决,还无法区分阴影部分是黑色还是白色。 因为两种的情况不同,所以处理方式也不同。阴影部分为黑底时需要转灰度和二值化,为白底时不需要。黑底使用归一化平方差匹配算法 TM_SQDIFF ,而白底使用相关系数匹配算法 TM_CCOEFF。

到此这篇关于使用java + selenium + OpenCV破解网易易盾滑动验证码的文章就介绍到这了,更多相关java滑动验证码内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

原文链接:https://blog.csdn.net/weixin_49701447/article/details/109740160

查看更多关于使用java + selenium + OpenCV破解网易易盾滑动验证码的示例的详细内容...

  阅读:74次