基于opencv实现对滑动验证码的识别及处理

 作者声明:

本程序并不鼓励各位读者违反京东平台的使用条款及相关法律规定!本文章仅作为学习交流和提供思路使用!  相关重要程序已对部分代码进行模糊处理!

import time
import base64
import re
from io import BytesIO
import cv2
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import os
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt

一、保存滑块和背景图

实际上获取这两个图片一点都不复杂甚至可以说是非常简单,只需要会一点点爬虫:

d9c8511e8bcc42fc8f3aae01aab2cfd6.png

只需要提取到src标签,然后解码即可:

small_img = driver.find_element(By.CSS_SELECTOR, '.JDJRV-img-panel .JDJRV-smallimg img ')
small_img_src = small_img.get_attribute("src")
base64_str_small = re.sub(r'^data:image/.+;base64,', '', small_img_src)
# 使用小图的解码数据
image_data_small = base64.b64decode(base64_str_small)  
# 创建小图对象
image_small = Image.open(BytesIO(image_data_small))  

二、分析滑块提取轮廓

# 加载滑块图
img_path = "你的滑块图路径" 
img = cv2.imread(img_path)
# 转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 假设我们选择 100 到 200 之间的灰度值
lower_gray = 100
upper_gray = 200
# 创建二值化掩码,只保留指定范围内的灰度
mask = cv2.inRange(gray, lower_gray, upper_gray)
# 找到轮廓
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 创建一个副本用于绘制
img_with_contours = img.copy()
# 绘制轮廓
for contour in contours:
# 用绿色线条绘制
    cv2.drawContours(img_with_contours, [contour], -1, (0, 255, 0), 1) 
# 找到最大的轮廓,并计算其外接矩形
if contours:
    max_contour = max(contours, key=cv2.contourArea)
# 获得外接矩形
    x, y, w, h = cv2.boundingRect(max_contour)
# 用绿色矩形标记
    cv2.rectangle(img_with_contours, (x, y), (x + w, y + h), (0, 255, 0), 2) 

52a7be4a7dd84431bd40febbaa435da5.png

三、获取滑动块在背景图上的位置信息

8b2c238dee284dcfa31e7ce0e6b65ffb.png

    element =driver.find_element(By.CSS_SELECTOR,'.JDValidate-wrap .JDJRV-img-panel .JDJRV-smallimg ')
    # 获取 style 属性
    style_value = element.get_attribute("style")
    # 解析 style 属性中的 top 和 width
    top_value_str = re.search(r'top:\s*([0-9.]+)px', style_value).group(1)
    width_value_str = re.search(r'width:\s*([0-9.]+)px', style_value).group(1)
    # 转换为数值
    top_value = float(top_value_str)
    width_value = float(width_value_str)
    # 计算滑块的上下边界
    # 滑块的顶部位置
    slider_top = top_value
    # 滑块的高度(根据 width 推断)
    slider_height = width_value
    # 滑块的底部位置
    slider_bottom = slider_top + slider_height

    print("Top value:", slider_top)
    print("Bottom value:", slider_bottom)

四、裁剪干扰部分并匹配颜色和轮廓

    # 获取背景图
    big_img = driver.find_element(By.CSS_SELECTOR, '.JDJRV-img-panel .JDJRV-bigimg img ')
    big_img_src = big_img.get_attribute("src")

    # 处理 Base64 数据
    base64_str_big = re.sub(r'^data:image/.+;base64,', '', big_img_src)
    image_data_big = base64.b64decode(base64_str_big)
    image_big = Image.open(BytesIO(image_data_big))

    # 创建存储目录
    output_dir = "images"
    os.makedirs(output_dir, exist_ok=True)

    # 将背景图转换为 OpenCV 格式
    background_img = cv2.cvtColor(np.array(image_big), cv2.COLOR_RGB2BGR)

    # 调整背景图尺寸为 242x94
    resized_background_img = cv2.resize(background_img, (242, 94))

    # 裁剪背景图
    crop_margin = 36
    y1 = int(slider_top )
    y2 = int(slider_bottom )

    cropped_background = resized_background_img[y1:y2, crop_margin:-crop_margin]

    # 首先计算每个像素的 RGB 平均值
    mean_rgb = np.mean(cropped_background, axis=2)  # 计算每个像素的 RGB 平均值

    # 创建掩码,确保平均值大于等于10,小于等于90
    mask = (mean_rgb >= 10) & (mean_rgb <= 90)  # 符合条件的布尔掩码
    mask = mask.astype(np.uint8) * 255  # 转换为二值掩码 (0 和 255)

    # 提取轮廓
    contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    # 获取滑动块图像
    slider_img_path = os.path.join(output_dir, "huaKuai_image.png")
    slider_img = cv2.imread(slider_img_path)

    # 转换为灰度并二值化
    gray_slider = cv2.cvtColor(slider_img, cv2.COLOR_BGR2GRAY)
    _, binary_slider = cv2.threshold(gray_slider, 100, 200, cv2.THRESH_BINARY)

    slider_contours, _ = cv2.findContours(binary_slider, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    slider_contour = max(slider_contours, key=cv2.contourArea)

    # 最少尝试5次
    max_attempts = 5
    attempt = 0
    best_match = None
    lowest_diff = float("inf")

    while attempt < max_attempts:
        for contour in contours:
            similarity = cv2.matchShapes(slider_contour, contour, cv2.CONTOURS_MATCH_I1, 0)
            if similarity < lowest_diff:
                area = cv2.contourArea(contour)
               # 检查面积在 400 到 1500 之间
                if 400 < area < 1400: 
                    best_match = contour
                    lowest_diff = similarity
                    break  

        attempt += 1

        if best_match is not None:
            break  

    if best_match is not None:
        x, y, w, h = cv2.boundingRect(best_match)
        cv2.rectangle(cropped_background, (x, y), (x + w, y + h), (0, 255, 0), 2)


        the_distance=x+36

        # 保存图像
        output_path = os.path.join(output_dir, "matched_image.png")
        cv2.imwrite(output_path, cropped_background)

        # 显示结果
        plt.imshow(cv2.cvtColor(cropped_background, cv2.COLOR_BGR2RGB))
        plt.title("Best Match with Area Check")
        plt.axis("off")
        plt.show()
    else:
        print("未找到满足条件的轮廓")

    do_actionchains(driver, the_distance)

3afd9cd1fdd94f898e68eee6d569a100.png

五、拖动滑块实现登录

这里不做演示,尽量模拟人类拖动验证码的习惯,否则即使完全重合也会登陆失败!

 

  • 30
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值