极验验证码的破解2-图片还原和滑块位置求解

上一章我们讨论了破解极验验证码的思路和步骤,这一章我将介绍如何还原两张背景图和求解滑块的目标位置。

一、图片还原

我们首先看看页面上给了我们什么参数:

image

这个是完整的背景图(fullbg)的页面元素,可以看到他们都是来自于同一张原图,只是截取的位置不同。上图红框就是该小图片在原图中的位置,每一张小图片都是10个像素宽,58个像素高,我们再来看看原图:

image

确实很乱,根本看不出什么东西。如果我们把这个原图下载下来,然后按照页面上的参数截取一个个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;
        }
    }
复制代码

带洞的背景图也是一样的处理,现在看看我们还原后的两张背景图:

image

二、求解滑块移动目标位置

有了第一步的结果,我们只需要对比两张背景图的像素,从左往右扫描即可找到滑块的目标位置了,还是看代码:

复制代码
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;
    }
复制代码

值得注意的是,比较像素的时候要设置一个容差值,可能是两张背景图经过多次处理存在了一定的像素差异,也可能是有个水印。

求解出滑块的目标位置后,我们是不是直接按照这个位移来拖动滑块就行了呢?答案是否定的,看下图:

image

可以看到在滑动之前滑块与背景图就已经存在一个距离了,需要做一个位移的调整,经过观察,这个值大概是7个像素,因此:最终滑动位移=求解出的滑块left像素个数-7。

下一章我将介绍如何使用模拟浏览器来加载和渲染页面。

仅此而已
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值