[Verification code recognition] NetEase Easy Shield sliding verification code

Use java + selenium + OpenCV to crack NetEase Easy Shield sliding verification code

* 验证码地址:https://dun.163.com/trial/jigsaw
* 使用OpenCv模板匹配
* Java + Selenium + OpenCV

The
Insert picture description here
Insert picture description here
next step is to witness the miracle!
Insert picture description here

Insert picture description here
note! ! !
· When simulating sliding, you cannot slide at the same speed or too fast. It needs to be as fast and then slow as when you slide, so that it is not easy to be recognized.
Simulate sliding code↓↓↓

/**
	 * 模拟人工移动
	 * @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;
	}

Operation process

Insert picture description here

/**
	 * 获取网易验证滑动距离
	 * 
	 * @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;
	}

Note: There is a problem that has not been resolved, and it is impossible to distinguish whether the shadow part is black or white. Because the two situations are different, the processing methods are also different. When the shaded part is black, it needs to be converted to grayscale and binarized, but not when it is white. The black background uses the normalized square difference matching algorithm TM_SQDIFF, and the white background uses the correlation coefficient matching algorithm TM_CCOEFF.

Those who have found a way to distinguish can privately message the author or leave a message in the comment area.

Insert picture description here

Author: taro-flavored cat Dian
stamp here → Kankan your mobile phone number registered at how many sites! ! !
Friendly recommendation: a new generation of secure SMS

Guess you like

Origin blog.csdn.net/weixin_44549063/article/details/112193516