小红书滑块验证码

背景

最近在维护公司之前的小红书采集代码,其中详情页采集使用的是web直接采集,由于请求频率蛮高的就有了弹滑块验证的问题,之前靠人手滑,但昨天网站仿佛抽风了一样无限弹滑块验证,于是着手开发自动滑块功能。

情况

滑块验证大概就长这样
在这里插入图片描述
在出现这种页面的时候你拿cookie无论怎么访问,都返回不了正确结果,因此需要将这个划开。

代码编写

下载图片

第一步肯定是先把图片下载下来,主要是两张图片,背景图和滑块图,就是红框和蓝框部分
在这里插入图片描述

计算滑动距离

然后是要知道滑动距离,大概就是下图图示的长度
在这里插入图片描述
那问题来了,怎么拿呢,用的方法是基于opencv中的Imgproc,也就是图像处理。那处理缺口图片的方法就用在小学二年级都学过的 灰度化+二值化,这里用的是阈值二值化。话不多说直接上代码

    public static Integer getXiaohongshuDistance(String backgroundPath, String slidePath) {
        OpenCV.loadShared();
        //处理背景图片
        Mat background = Imgcodecs.imread(backgroundPath);
        background = resize(background, 400, 200);
        Imgcodecs.imwrite("e:/tmp/xiaohongshu_bg_400x200.png", background);
        Mat backgroundGrey = new Mat();
        //灰度化
        Imgproc.cvtColor(background, backgroundGrey, Imgproc.COLOR_RGB2GRAY);
        Mat backgroundBit = new Mat();
        //阈值二值化
        Imgproc.threshold(backgroundGrey, backgroundBit, 175, 255, Imgproc.THRESH_BINARY_INV);
        Imgcodecs.imwrite("e:/tmp/xiaohongshu_bg_bit.png", backgroundBit);
        //处理滑块图片
        Mat slide = Imgcodecs.imread(slidePath, IMREAD_UNCHANGED);
        slide = resize(slide, 60, 200);
        Imgcodecs.imwrite("e:/tmp/xiaohongshu_bg_60x200.png", slide);
        Rect opaqueArea = getOpaqueArea(slide);
        Mat crop = crop(slide, opaqueArea);
        //将所有不透明的全部变白
        fillWhiteBackgroundColor(crop);
        Mat slideGrey = new Mat();
        Imgproc.cvtColor(crop, slideGrey, Imgproc.COLOR_RGB2GRAY);
        Mat slideBit = new Mat();
        Imgproc.threshold(slideGrey, slideBit, 254, 255, Imgproc.THRESH_BINARY);
        Imgcodecs.imwrite("e:/tmp/xiaohongshu_slide_bit.png", slideBit);
        //匹配模板
        Mat matchResult = new Mat();
        Imgproc.matchTemplate(backgroundBit, slideBit, matchResult, Imgproc.TM_CCOEFF_NORMED);
        Rect rect = new Rect(0, opaqueArea.y - 3, matchResult.width(), 7);
        matchResult = crop(matchResult, rect);
        Core.MinMaxLocResult minMaxLocResult = Core.minMaxLoc(matchResult);
        Double x = minMaxLocResult.maxLoc.x;
        return x.intValue() - opaqueArea.x;
    }
    public static Mat resize(Mat img, Integer width, Integer height) {
        Mat result = new Mat();
        Imgproc.resize(img, result, new Size(width, height));
        return result;
    }

    public static Rect getOpaqueArea(Mat slide) {
        Set<Integer> xProjection = new HashSet<>();
        Set<Integer> yProjection = new HashSet<>();
        for (int i = 0; i < slide.height(); i++) {
            for (int j = 0; j < slide.width(); j++) {
                Double alpha = slide.get(i, j)[3];
                if (alpha >= 255.0) {
                    xProjection.add(j);
                    yProjection.add(i);
                }
            }
        }
        Integer minX = Collections.min(xProjection);
        Integer maxX = Collections.max(xProjection);
        Integer minY = Collections.min(yProjection);
        Integer maxY = Collections.max(yProjection);
        Rect rect = new Rect(minX, minY, maxX - minX + 1, maxY - minY + 1);
        return rect;
    }

    public static Mat crop(Mat slide, Rect rect) {
        Mat crop = new Mat(slide, rect);
        Mat result = new Mat();
        crop.copyTo(result);
        return result;
    }

    public static void fillWhiteBackgroundColor(Mat slide) {
        for (int i = 0; i < slide.height(); i++) {
            for (int j = 0; j < slide.width(); j++) {
                Double alpha = slide.get(i, j)[3];
                if (alpha < 255.0) {
                    double[] whitePoint = {255.0, 255.0, 255.0, 255.0};
                    slide.put(i, j, whitePoint);
                }
            }
        }
    }

如果看代码还有点不清楚的话,看处理结果图片应该就知道了
在这里插入图片描述
在这里插入图片描述

生成滑动距离列表

得到了滑动距离之后怎么做,直接一步到位直接匀速直线运动全划了?那怕不是直接告诉网站“我是个机器人”。肯定要表现得像个人一样,这里直接用抄来的一段加速度模型。

public static List<Integer> generateTrackers(Integer distance) {
        List<Integer> forwardTrackers = new ArrayList<>();
        Double overDistance = distance + 20.0;
        Double v = 0.0;
        Double t = 0.5;
        Double current = 0.0;
        Double mid = overDistance * 3 / 5;
        while (current < overDistance) {
            Double a;
            if (current < mid) {
                a = 2.0;
            } else {
                a = -3.0;
            }
            Double s = v * t + 0.5 * a * t * t;
            v = v + a * t;
            current += s;
            Integer sInt = (int) Math.round(s);
            forwardTrackers.add(sInt);
        }
        Integer sum = 0;
        for (Integer s : forwardTrackers) {
            sum += s;
        }
        sum = sum - distance - 16;
        List<Integer> backTrackers = new ArrayList<>();
        backTrackers.add(-3);
        backTrackers.add(-3);
        backTrackers.add(-2);
        backTrackers.add(-2);
        backTrackers.add(-2);
        backTrackers.add(-2);
        backTrackers.add(-2);
        for (int i = 0; i < sum; i++) {
            backTrackers.add(-1);
        }
        forwardTrackers.addAll(backTrackers);
        return forwardTrackers;
    }

这段代码的目的是生成一个单次滑动距离的滑动列表。

执行

拖动按钮滑动

public static void performSlide(ChromeDriver driver, WebElement dragButton, List<Integer> trackers) {
        PointerInput defaultMouse = new PointerInput(MOUSE, "default mouse");
        Interaction move = defaultMouse.createPointerMove(Duration.ofMillis(100l), PointerInput.Origin.fromElement(dragButton), 0, 0);
        Sequence sequence = new Sequence(move.getSource(), 0);
        sequence.addAction(move);
        Interaction buttonDown = defaultMouse.createPointerDown(PointerInput.MouseButton.LEFT.asArg());
        sequence.addAction(buttonDown);
        for (int i = 0; i < trackers.size(); i++) {
            Interaction moveByOffset = defaultMouse.createPointerMove(Duration.ofMillis(20l+new Random().nextInt(5)), PointerInput.Origin.pointer(), trackers.get(i), new Random().nextInt(2));
            sequence.addAction(moveByOffset);
        }
        Interaction buttonUp = defaultMouse.createPointerUp(PointerInput.MouseButton.LEFT.asArg());
        sequence.addAction(buttonUp);
        List<Sequence> sequences = new ArrayList<>();
        sequences.add(sequence);
        driver.perform(sequences);
    }
滑动拼图验证码小红书中的应用类似于其他网站。滑动拼图验证码是一种人机验证机制,通过用户拖动滑块将缺口对齐,以证明用户是真实的人类,而不是自动化程序或恶意机器人。 具体到小红书的实现,根据引用中提供的代码,可以看到它使用了一个名为`slideverify`的自定义组件。这个组件接受一些参数,如滑块宽度、滑块高度、滑块位置等,并提供了一些回调函数,如`onSuccess`、`onRefresh`等。 其中,`getImageVerifyCode`函数用于获取验证码图片,并将图片的地址赋值给`imgurl`和`miniimgurl`。`imgurl`存储原始大小的验证码图片地址,`miniimgurl`存储缩略图的验证码图片地址。 `onRefresh`函数用于刷新验证码,它会清空`imgurl`和`miniimgurl`的值,并重新调用`getImageVerifyCode`函数获取新的验证码图片。 `onSuccess`函数在滑动结束后,将滑动的距离作为参数传入,并调用`verifyImageCode`函数进行后台验证。根据后台返回的验证结果,如果通过则显示成功信息,否则显示错误信息,并调用`onRefresh`函数刷新验证码。 总的来说,滑动拼图验证码小红书中的实现是通过自定义组件和一些回调函数来完成的,它增加了用户与机器的交互,提高了系统的安全性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Vue实现滑动拼图验证码功能](https://download.csdn.net/download/weixin_38747917/14818686)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [3分钟使用Halcon识别网易滑块拼图验证码](https://blog.csdn.net/qq_29888333/article/details/84192678)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Java Vue uni-app 三端实现,滑动拼图验证码](https://blog.csdn.net/qq_32698323/article/details/118876646)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值