告别手动拖动!Python+dddocr自动化破解多缺口滑块

本文适合新手小白,带你一步步实现自动化通过多缺口滑块验证,助你轻松应对反爬虫难题!

一、什么是滑块验证?

滑块验证是一种常见的反爬虫手段,用户需要按住滑块拖动到指定位置,才能通过验证。多缺口滑块验证则是在背景图上有多个缺口,滑块需要精确拖动到正确的缺口位置。

手动操作很简单,但自动化通过却难倒了不少爬虫新手。本文将带你用 Python + DrissionPage 实现自动化滑块验证。


二、核心思路

  1. 识别滑块和背景图:获取页面上的滑块和背景图片。
  2. 识别缺口位置:用 OCR 或图像处理算法识别缺口的准确位置。
  3. 模拟人类拖动滑块:用代码模拟鼠标按下、移动、释放,完成滑块验证。

三、代码实战

1. 环境准备

  • Python 3.8+
  • DrissionPage
  • pillow(用于图片处理)
  • ddddocr(滑块识别)
bash 复制代码
pip install DrissionPage pillow ddddocr

2. 主要代码结构

2.1 滑块识别核心:recognize_slider_distance

滑块验证的关键是如何准确识别滑块需要移动的距离。下面详细讲解 recognize_slider_distance 的实现原理和代码:

python 复制代码
import base64
import numpy as np
from PIL import Image
import io
import ddddocr

def base64_decode(str):
    return base64.b64decode(str)

def slider_puzzle_qg(p_puzzle_path: str = ''):
    """
    将小拼图去除透明边缘,返回处理后的base64图片和位置信息
    """
    image = Image.open(p_puzzle_path)
    width, height = image.size
    pixels = image.load()
    _a = 0  # 顶部透明行数
    _b = 0  # 有效拼图高度
    _c = 0  # 底部透明行数
    k = []  # 有效像素
    buffered = io.BytesIO()
    for x in range(height):
        data_pixel = []
        for y in range(width):
            r, g, b, a = pixels[y, x]
            data_pixel += [(r, g, b, a)]
        NumPy_data_pixel = np.array(data_pixel)
        if np.all(NumPy_data_pixel == 0):
            if _b == 0:
                _a += 1
            else:
                if _c == 0:
                    new_image = Image.new('RGBA', (width, _b), color=(0, 0, 0, 0))
                    new_image.putdata(k)
                    new_image.save(buffered, format="PNG")
                _c += 1
        else:
            _b += 1
            k += data_pixel
    return {
        '最顶层-顶层距离': _a,
        '中间层-拼图的高度': _b,
        '最底层-底层距离': _c,
        'base64': base64.b64encode(buffered.getvalue()).decode()
    }

def background_cutting(b_puzzle_path: str = '', b_size_h: int = 0, p_size_h: int = 0):
    """
    按小拼图的高度切割背景图,返回base64
    """
    image = Image.open(b_puzzle_path)
    width, height = image.size
    left, right = 0, width
    top, bottom = b_size_h, b_size_h + p_size_h
    cropped_image = image.crop((left, top, right, bottom))
    buffered = io.BytesIO()
    cropped_image.save(buffered, format="PNG")
    return {'base64': base64.b64encode(buffered.getvalue()).decode()}

def recognize_slider_distance(xiaopintu_path, beijingtu_path):
    """
    识别滑块需要移动的距离
    :param xiaopintu_path: 小拼图路径
    :param beijingtu_path: 背景图路径
    :return: 滑动距离
    """
    det = ddddocr.DdddOcr(det=False, ocr=False, show_ad=False)
    xiaopintu_data = slider_puzzle_qg(p_puzzle_path=xiaopintu_path)
    beijingtu_data = background_cutting(b_puzzle_path=beijingtu_path, b_size_h=xiaopintu_data['最顶层-顶层距离'],
                                        p_size_h=xiaopintu_data['中间层-拼图的高度'])
    res1 = det.slide_match(base64_decode(beijingtu_data['base64']), base64_decode(xiaopintu_data['base64']),
                           simple_target=True)
    res1 = res1['target'][0]
    # 为了更像人类操作,可以加一点偏移
    res = res1 * 1.1 - 4
    return res

原理说明:

  • 先用 slider_puzzle_qg 去除小拼图的透明边缘,获得有效区域和高度。
  • background_cutting 按小拼图的高度切割背景图,获得滑道。
  • 用 ddddocr 的 slide_match 方法,计算小拼图在滑道中的最佳匹配位置(即缺口横坐标)。
  • 最后加一点偏移,模拟人类误差,防止被反爬虫检测。

2.2 登录与滑块拖动

下面是完整的登录与滑块拖动自动化代码示例,适合新手理解:

python 复制代码
import random
import time
import base64
from DrissionPage import Chromium, ChromiumOptions
from utils.ocr_util import recognize_slider_distance  # 上文已详细讲解
from service.logger import logger

# 创建浏览器实例
co = ChromiumOptions().set_browser_path(r'C:\Path\To\chrome.exe')
tab = Chromium().latest_tab

def base64_decode(data):
    return base64.b64decode(data + '==')

def login_with_slider(tab, username, password):
    try:
        # 1. 打开登录页面(URL已脱敏)
        tab.get('https://your-domain.com/login')
        # 2. 输入账号密码
        username_ele = tab.ele('@@tag()=input@@placeholder=请输入账号')
        password_ele = tab.ele('@@tag()=input@@placeholder=请输入密码')
        username_ele.input(username)
        password_ele.input(password)
        # 3. 点击登录按钮
        login_button = tab.ele('@@tag()=span@@text():登 录')
        login_button.click(by_js=True)

        # 4. 获取滑块和背景图片
        background_image_ele = tab.ele('@@tag()=div@@class=verify-img-panel').ele('@@tag()=img')
        gap_image_ele = tab.ele('@@tag()=div@@class=verify-sub-block').ele('@@tag()=img')
        xiaopintu_data = gap_image_ele.attr('src').split("data:image/png;base64,")[-1]
        background_img_data = background_image_ele.attr('src').split("data:image/png;base64,")[-1]
        with open('beijingtu.png', 'wb') as f:
            f.write(base64_decode(background_img_data))
        with open('xiaopintu.png', 'wb') as f:
            f.write(base64_decode(xiaopintu_data))

        # 5. 识别滑块需要移动的距离
        distance = recognize_slider_distance(xiaopintu_path="xiaopintu.png", beijingtu_path="beijingtu.png")
        tab.wait.ele_displayed('@@tag()=div@@class=verify-move-block', timeout=10)
        slider = tab.ele('@@tag()=div@@class=verify-move-block').wait.clickable(timeout=10)
        if not slider:
            logger.error('未找到滑块元素,请检查类名或页面结构')
            return False
        else:
            tab.run_js('arguments[0].style.border="2px solid red"', slider)
            logger.info(' 找到滑块元素,开始滑动')
            # 6. 获取滑块中心点坐标
            slider_rect = tab.run_js('''
                const rect = arguments[0].getBoundingClientRect();
                return {
                    x: rect.x + rect.width / 2,
                    y: rect.y + rect.height / 2
                }
            ''', slider)
            try:
                # 7. 用 JS 模拟鼠标事件拖动滑块
                tab.run_js('''
                    function simulateMouseEvent(element, eventType, x, y) {
                        const event = new MouseEvent(eventType, {
                            view: window,
                            bubbles: true,
                            cancelable: true,
                            clientX: x,
                            clientY: y
                        });
                        element.dispatchEvent(event);
                    }
                    const slider = arguments[0];
                    const startX = arguments[1];
                    const startY = arguments[2];
                    const distance = arguments[3];
                    simulateMouseEvent(slider, 'mousedown', startX, startY);
                    const segments = 5;
                    const segmentDistance = distance / segments;
                    let currentX = startX;
                    for (let i = 0; i < segments; i++) {
                        currentX += segmentDistance;
                        simulateMouseEvent(slider, 'mousemove', currentX, startY);
                    }
                    currentX -= 5;
                    simulateMouseEvent(slider, 'mousemove', currentX, startY);
                    simulateMouseEvent(slider, 'mouseup', currentX, startY);
                ''', slider, slider_rect['x'], slider_rect['y'], distance)
                logger.info(' 滑动操作已发送')
                time.sleep(1)
            except Exception as e:
                logger.error(f' 滑动出错: {e}')
                return False
        # 8. 后续验证、UKey等操作略
        return True
    except Exception as e:
        logger.error(f"登录失败,错误信息:{e}")
        return False

代码说明:

  • 步骤1-3:自动化输入账号、密码并点击登录。
  • 步骤4:获取滑块和背景图片,保存为本地文件。
  • 步骤5:调用 recognize_slider_distance 识别滑块需要移动的距离。
  • 步骤6:获取滑块元素的中心点坐标。
  • 步骤7:用 JavaScript 分段模拟鼠标拖动滑块,模拟人类操作。此处也可以使用drisionpage操作元素例如:
bash 复制代码
# 向右移动鼠标
# tab_.actions.right(distance - 10)
time.sleep(0.05)
# tab_.actions.right(10)
  • 步骤8:后续如UKey验证等可根据实际需求补充。

3. 关键技术点说明

  • 图片识别recognize_slider_distance 利用 ddddocr 的滑块识别能力,极大简化了滑块距离的计算。
  • 图片预处理:去除透明边缘、切割滑道,是提升识别准确率的关键。
  • JS 模拟鼠标事件 :直接用 JS 触发 mousedownmousemovemouseup,比传统动作链更容易绕过部分反爬虫。
  • 分段移动:模拟人手抖动,分多段移动更像真人。
  • 异常处理:每一步都要加 try/except,方便调试。

四、常见问题与排查

  1. 滑块没动?
    • 检查元素选择器是否准确。
    • 检查 JS 事件是否被页面拦截。
    • 尝试加大分段数,或调整每段距离。
  2. 识别距离不准?
    • 检查图片保存是否完整。
    • 调整识别算法参数。
    • 检查小拼图和背景图的预处理是否正确。
  3. 验证失败?
    • 检查是否有额外的行为验证(如轨迹分析、行为分析)。
    • 尝试加大拖动时间,模拟更慢的拖动。

五、总结

自动化通过多缺口滑块验证并不神秘,关键在于:

  • 正确识别滑块和缺口位置(图片预处理+滑块识别)
  • 用 JS 或动作链模拟真实拖动
  • 多调试、多尝试,遇到问题多看日志

希望这篇教程能帮你迈出自动化滑块验证的第一步!


温馨提示:请勿将本教程用于非法用途,合理合规使用自动化技术。

相关推荐
测试199811 分钟前
如何编写好的测试用例?
自动化测试·软件测试·python·功能测试·测试工具·职场和发展·测试用例
Dreamsi_zh27 分钟前
Python爬虫04_Requests豆瓣电影爬取
开发语言·爬虫·python
230L1_78M69Q5487H28 分钟前
【机器学习】机器学习新手入门概述
人工智能·python·机器学习·scikit-learn
窗户1 小时前
有限Abel群的结构(3)
python·抽象代数·编程范式
饭来_1 小时前
Python 中使用 OpenCV 库来捕获摄像头视频流并在窗口中显示
python·opencv
码界筑梦坊1 小时前
91-基于Spark的空气质量数据分析可视化系统
大数据·python·数据分析·spark·django·numpy·pandas
坐吃山猪1 小时前
GitPython03-项目setup编译
git·python·setup
JavaEdge在掘金2 小时前
cursor1.3 重大更新!复刻 claude code!
python
啊阿狸不会拉杆2 小时前
《Java 程序设计》第 12 章 - 异常处理
java·开发语言·jvm·python·算法·intellij-idea
lili-felicity2 小时前
Python奇幻之旅:从零开始的编程冒险
python