python爬虫模拟拖动滑块缺口验证码

目录

一、滑块验证码

二、破解思路

三、代码实现

3.1、自动化方式

3.2、接口方式

四、总结


一、滑块验证码

滑块验证码有:滑动缺口验证码、滑动滚动条验证码,滚动条比较简单,只需要计算右侧(通常是往右滑动)的距离。需要用户拖动解决的,还有旋转验证码等变体,本文注意介绍通过使用DrissionPage及ddddocr来破解缺口类型的验证码。

二、破解思路

需要破解滑动验证码,首先要确定缺口目标及背景板,然后计算出缺口在背景图上的坐标位置,同时为了更好的计算坐标位置,有种方法是对背景缺口进行切割,切割掉缺口的右侧,这样会使坐标计算更准确。在python中常用的方式有自动化、接口破解相关方式。

三、代码实现

3.1、自动化方式

python自动化工具有selenium、drissionpage等,本文演示使用drissionpage来操作自动化模拟滑块验证码操作。

python 复制代码
from DrissionPage import ChromiumPage, ChromiumOptions
import base64, ddddocr, time, random
from io import BytesIO
from PIL import Image
import json, traceback


co = ChromiumOptions()
co.no_imgs(False)
# Linux必需配置
co.set_argument('--headless')
co.set_argument('--no-sandbox')
co.set_argument('--disable-gpu')
co.set_argument('--disable-dev-shm-usage')
co.set_argument('--disk-cache-dir=/tmp/chrome_cache')
# 解决端口冲突问题
co.set_argument('--remote-debugging-port=0')  # 让系统自动分配可用端口
co.set_argument('--remote-allow-origins=*')
# 确保使用headless模式
co.set_argument('--headless=new')
# 模拟真实浏览器行为
co.set_argument('--disable-blink-features=AutomationControlled')
co.set_argument('--disable-infobars')
co.set_argument('--disable-web-security')
co.set_argument('--allow-running-insecure-content')
co.set_user_agent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36')
# 禁用自动化标志
co.set_pref('excludeSwitches', ['enable-automation'])
co.set_pref('useAutomationExtension', False)
page = ChromiumPage(co)

# 监听的验证码接口
page.listen.start('/api/captcha/get')

# 登录以触发验证码
page.ele('@placeholder=请输入账号').input(self.username)
page.ele('@placeholder=请输入密码').input(self.password)
page.ele('登 录').click()

time.sleep(1)

packet = page.listen.wait(timeout=30)  # 等待验证码接口响应
if not packet:
    raise Except('未获取到验证码接口响应')

# 验证码接口返回
originalImageBase64 = packet.response.body['data']['repData']['originalImageBase64']
jigsawImageBase64 = packet.response.body['data']['repData']['jigsawImageBase64']
target_bytes = base64.b64decode(jigsawImageBase64)
background_bytes = base64.b64decode(originalImageBase64)

# 借助ddddocr计算滑块距离
det = ddddocr.DdddOcr(det=False, ocr=False, show_ad=False)
det.slide_match(target_bytes, background_bytes)
target_x = res['target'][0]

# 定位到滑块元素
slider_ele = page.ele('@class=verify-left-bar')
if not slider_ele:
    raise Except('未定位到滑动元素')

# 滑动滑块,随机抖动,模拟人为操作
random_list = [3, 2, 1, 0, -1, -2, -3]
"""
这里offset_x的取值是因为ddddocr识别的是根据背景图的x、y来计算的,与实际页面值不一样,所以这里需要对计算出来的值进行转换。其中380为背景图宽度、360为实际页面滑块区域可拖动宽度(真实场景下应该定位到元素求出真实的宽度,而不是写死)。常用转换公式有以下几种:
1、int(x * image_width / track_width)
2、x * image_width // track_width
"""
page.actions.move_to(slider_ele ).hold().move(offset_x=x * 380 // 360 + random.choice(random_list), duration=.3).release()

# 后续再通过监听login接口或者定位登录成功后的元素来判断是否成功。

3.2、接口方式

大体逻辑一致,只是不通过自动化工具启动的浏览器,更轻量化,更推荐使用的。同样要借助ddddocr来识别缺口位置,然后调用接口来完成无感滑动。

python 复制代码
import base64
from typing import Tuple
import ddddocr
from PIL import Image
import io
import base64
from six import BytesIO


def calculate_min_xy_coordinates(jigsaw_image_bytes: bytes) -> Tuple[int, int]:
    """
    计算滑块图片的最小 x 和 y 坐标(有效区域的最左侧和最上侧)。
    """
    try:
        image_stream = BytesIO(jigsaw_image_bytes)
        img = Image.open(image_stream)
        width, height = img.size
        min_x = float("inf")
        min_y = float("inf")

        for x in range(width):
            for y in range(height):
                pixel = img.getpixel((x, y))
                if len(pixel) == 4 and pixel[3] > 0:
                    min_x = min(min_x, x)
                    min_y = min(min_y, y)

        return (
            min_x if min_x != float("inf") else 0,
            min_y if min_y != float("inf") else 0,
        )
    except Exception as exc:
        print(f"处理滑块图像出错: {exc}")
        return 0, 0


# 1、请求滑块验证码接口,拿到缺口图及背景图(为节省代码,这里假设已经拿到了)
target_bytes = base64.b64decode(jigsaw_base64)
background_bytes = base64.b64decode(original_base64)

# 2、计算滑块(应对有干扰滑块时,切掉头顶及右侧干扰区域,目的为了ddddocr能识别的更准确)
slider_img_x_px, slider_img_y_px = calculate_min_xy_coordinates(target_bytes )
with Image.open(io.BytesIO(background_bytes)) as img:
	width, height = img.size
	cropped_background = img.crop((0, slider_img_y_px , width, height))
	cropped_background_bytes = BytesIO()
	cropped_background.save(cropped_background_bytes, format="PNG")
	cropped_background_bytes.seek(0)

# 3、识别距离
"""
其实第二步可以不用做,直接使用缺口图和背景图,ddddocr也可以精准识别(🤡)
"""
det = ddddocr.DdddOcr(det=False, ocr=False, show_ad=False)
result = det.slide_match(target_bytes, cropped_background_bytes.read())
origin_x = result ["target"][0]
x = origin_x - slider_img_x_px
offset_x = x * 380 // 360
print(f"经ddddocr计算,得出滑块与缺口间距离:{offset_x}(px)")
return int(offset_x)

四、总结

功能类别 解决的问题 对应的 ddddocr 方法 典型应用场景
图片验证码 识别图片中的内容 classification() 识别数字、字母、中英文混合的静态图片验证码
滑块验证码 计算滑块缺口的位置 slide_match() 拖动滑块至缺口处完成验证
点选验证码 检测并定位图中多个目标的坐标 detection() 按顺序点击图片中的文字或物体(如"请依次点击:书、杯子")
计算验证码 识别数学算式并计算结果 classification() + eval()处理 识别并计算出"23 + 9 = ?"这类验证码的结果
[ddddocr 核心功能一览(AI回答)]
相关推荐
AI分享猿1 小时前
用MonkeyCode做数据爬虫,效率提升10倍
爬虫
再玩一会儿看代码2 小时前
Java浅拷贝和深拷贝理解笔记
java·linux·开发语言·笔记·python·学习
love530love2 小时前
【笔记】ComfyUI 源码部署版更新后一键修复:从手动补丁到自动化工作流
运维·人工智能·windows·笔记·python·自动化·comfyui
石榴树下的七彩鱼2 小时前
发票OCR识别API接入教程:从图像到结构化数据的完整实战(附Python/Java/PHP/JS代码)
java·python·ocr·api接口·财务自动化·石榴智能·发票ocr
Wonderful U2 小时前
基于Python+Django的智能在线考试系统:从题库管理到自动阅卷的全流程实战
开发语言·python·django
SilentSamsara2 小时前
Python 服务的 K8s 部署:HPA/ConfigMap/Secret 完整配置
开发语言·python·青少年编程·容器·kubernetes
前端与小赵2 小时前
数据库交互全链路实战:通用封装、批量优化与动态查询三大核心模块
数据库·python·sql
盼小辉丶2 小时前
PyTorch强化学习实战(11)——N步DQN(N-step DQN)
pytorch·python·深度学习·强化学习
godspeed_lucip2 小时前
LLM和Agent——专题6:Multi Agent 入门(1)
人工智能·python