小红书滑块验证码

背景

最近在维护公司之前的小红书采集代码,其中详情页采集使用的是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);
    }
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
滑块验证码是一种常见的验证码形式,旨在验证用户是否为人类。PyTorch是一个开源的深度学习框架,可以用它来实现滑块验证码识别系统。 滑块验证码通常由两个部分组成:滑块图片和背景图片。滑块图片上有一个滑块,用户需要通过拖动滑块将其放到正确的位置,以完成验证。 要实现滑块验证码的识别,可以按照以下步骤进行: 1. 数据准备:收集大量的滑块验证码图片,并将其划分为训练集和测试集。训练集用于训练模型,测试集用于评估模型的性能。 2. 特征提取:使用PyTorch加载滑块验证码图片,并对其进行预处理。可以使用卷积神经网络(CNN)来提取图片的特征。 3. 训练模型:使用PyTorch构建一个深度学习模型,可以选择使用已经预训练好的模型作为基础模型,如ResNet、VGG等。然后,将提取的特征输入到模型中,通过反向传播来优化模型的参数。 4. 模型评估:使用测试集对训练好的模型进行评估,计算准确率、精度等指标,判断模型的性能。 5. 模型应用:将训练好的模型部署到实际的滑块验证码系统中,用户在登录或注册时需要完成验证码验证。用户拖动滑块,系统会根据用户的操作判断是否为真实用户。 通过使用PyTorch深度学习框架,我们可以方便地实现滑块验证码的识别。它提供了丰富的工具和算法,可以帮助我们构建高性能的滑块验证码识别系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值