上一章我们讨论了破解极验验证码的思路和步骤,这一章我将介绍如何还原两张背景图和求解滑块的目标位置。
一、图片还原
我们首先看看页面上给了我们什么参数:
这个是完整的背景图(fullbg)的页面元素,可以看到他们都是来自于同一张原图,只是截取的位置不同。上图红框就是该小图片在原图中的位置,每一张小图片都是10个像素宽,58个像素高,我们再来看看原图:
确实很乱,根本看不出什么东西。如果我们把这个原图下载下来,然后按照页面上的参数截取一个个10像素宽,58像素高的小图片拼接在一起便可以得到完整的背景图了,上代码:
/** * 合成指定的多张图片到一张图片 * * @param imgSrcList 图片的地址列表 * @param topLeftPointList 每张小图片的偏移量 * @param countOfLine 每行的小图片个数 * @param cutWidth 每张小图片截取的宽度(像素) * @param cutHeight 每张小图片截取的高度(像素) * @param savePath 合并后图片的保存路径 * @param subfix 合并后图片的后缀 * @return 是否合并成功 */ public static boolean combineImages(List<String> imgSrcList, List<String[]> topLeftPointList, int countOfLine, int cutWidth, int cutHeight, String savePath, String subfix) { if (imgSrcList == null || savePath == null || savePath.trim().length() == 0) return false; BufferedImage lastImage = new BufferedImage(cutWidth * countOfLine, cutHeight * ((int) (Math.floor(imgSrcList.size() / countOfLine))), BufferedImage.TYPE_INT_RGB); String prevSrc = ""; BufferedImage prevImage = null; try { for (int i = 0; i < imgSrcList.size(); i++) { String src = imgSrcList.get(i); BufferedImage image; if (src.equals(prevSrc)) image = prevImage; else { if (src.trim().toLowerCase().startsWith("http")) image = ImageIO.read(new URL(src)); else image = ImageIO.read(new File(src)); prevSrc = src; prevImage = image; } if (image == null) continue; String[] topLeftPoint = topLeftPointList.get(i); int[] pixArray = image.getRGB(0 - Integer.parseInt(topLeftPoint[0].trim()), 0 - Integer.parseInt(topLeftPoint[1].trim()), cutWidth, cutHeight, null, 0, cutWidth); int startX = ((i) % countOfLine) * cutWidth; int startY = ((i) / countOfLine) * cutHeight; lastImage.setRGB(startX, startY, cutWidth, cutHeight, pixArray, 0, cutWidth); } File file = new File(savePath); return ImageIO.write(lastImage, subfix, file); } catch (Exception ex) { ex.printStackTrace(); return false; } }
带洞的背景图也是一样的处理,现在看看我们还原后的两张背景图:
二、求解滑块移动目标位置
有了第一步的结果,我们只需要对比两张背景图的像素,从左往右扫描即可找到滑块的目标位置了,还是看代码:
public static int findXDiffRectangeOfTwoImage(String imgSrc1, String imgSrc2) { try { BufferedImage image1 = ImageIO.read(new File(imgSrc1)); BufferedImage image2 = ImageIO.read(new File(imgSrc2)); int width1 = image1.getWidth(); int height1 = image1.getHeight(); int width2 = image2.getWidth(); int height2 = image2.getHeight(); if (width1 != width2) return -1; if (height1 != height2) return -1; int left = 0; /** * 从左至右扫描 */ boolean flag = false; for (int i = 0; i < width1; i++) { for (int j = 0; j < height1; j++) if (isPixelNotEqual(image1, image2, i, j)) { left = i; flag = true; break; } if (flag) break; } return left; } catch (Exception ex) { ex.printStackTrace(); return -1; } } private static boolean isPixelNotEqual(BufferedImage image1, BufferedImage image2, int i, int j) { int pixel1 = image1.getRGB(i, j); int pixel2 = image2.getRGB(i, j); int[] rgb1 = new int[3]; rgb1[0] = (pixel1 & 0xff0000) >> 16; rgb1[1] = (pixel1 & 0xff00) >> 8; rgb1[2] = (pixel1 & 0xff); int[] rgb2 = new int[3]; rgb2[0] = (pixel2 & 0xff0000) >> 16; rgb2[1] = (pixel2 & 0xff00) >> 8; rgb2[2] = (pixel2 & 0xff); for (int k = 0; k < 3; k++) if (Math.abs(rgb1[k] - rgb2[k]) > 50)//因为背景图会有一些像素差异 return true; return false; }
值得注意的是,比较像素的时候要设置一个容差值,可能是两张背景图经过多次处理存在了一定的像素差异,也可能是有个水印。
求解出滑块的目标位置后,我们是不是直接按照这个位移来拖动滑块就行了呢?答案是否定的,看下图:
可以看到在滑动之前滑块与背景图就已经存在一个距离了,需要做一个位移的调整,经过观察,这个值大概是7个像素,因此:最终滑动位移=求解出的滑块left像素个数-7。
下一章我将介绍如何使用模拟浏览器来加载和渲染页面。
时间: 2024-12-25 20:43:43