在现代网络应用中,为了防止恶意爬虫和自动化脚本的攻击,验证码成为了保障安全的重要手段。滑动验证码是其中一种常见的形式,它要求用户通过滑动滑块来完成验证。本文将详细介绍如何使用 Python 编写代码来破解滑动验证码,同时模拟人类的操作轨迹,提高破解的成功率。

整体思路

破解滑动验证码的核心思路分为以下几个步骤:

  1. 获取背景图和滑动图:从网页中提取背景图和滑动图的 URL,并下载保存到本地。
  2. 计算滑动距离:使用 OpenCV 库进行模板匹配,找出滑动图在背景图中的位置,从而计算出需要滑动的距离。
  3. 生成移动轨迹:使用贝塞尔曲线生成模拟人类操作的移动轨迹。
  4. 模拟鼠标操作:使用 Puppeteer 或类似的工具模拟鼠标的滑动操作,完成验证码的验证。

代码实现

1. 生成贝塞尔曲线的坐标点

import random
import numpy as np
import bezier

def generate_bezier_curve(start_x, end_x, control_points=2):
    """
    生成贝塞尔曲线的坐标点
    :param start_x: 起始 x 坐标
    :param end_x: 结束 x 坐标
    :param control_points: 控制点数量
    :return: 贝塞尔曲线的 x 坐标列表
    """
    nodes = [
        [start_x] + [random.uniform(start_x, end_x) for _ in range(control_points)] + [end_x],
        [0] * (control_points + 2)
    ]
    curve = bezier.Curve(np.asfortranarray(nodes), degree=control_points + 1)
    samples = [curve.evaluate(t)[0][0] for t in [i / 30 for i in range(31)]]
    return samples

 2. 计算滑动距离

import cv2
import time

def get_move_x(image_path, template_path, image_height, image_width, template_height, template_width):
    # 背景图
    image = cv2.imread(image_path)
    image_resize = cv2.resize(image, (int(image_width), int(image_height)))
    # 处理图像,保留大部分白色
    ret, thresholded_image = cv2.threshold(image_resize, 220, 255, cv2.THRESH_BINARY)
    # 灰度图像
    gray_image1 = cv2.cvtColor(thresholded_image, cv2.COLOR_BGR2GRAY)
    # 提高对比度
    denoised_image1 = cv2.equalizeHist(gray_image1)
    # 边缘检测
    image_canny = cv2.Canny(denoised_image1, threshold1=500, threshold2=900)

    # 滑动图
    template = cv2.imread(template_path)
    template_resize = cv2.resize(template, (int(template_width), int(template_height)))
    template_gray = cv2.cvtColor(template_resize, cv2.COLOR_BGR2GRAY)
    denoised_image2 = cv2.equalizeHist(template_gray)
    template_canny = cv2.Canny(denoised_image2, threshold1=650, threshold2=900)

    # 进行模板匹配
    result = cv2.matchTemplate(image_canny, template_canny, cv2.TM_CCOEFF_NORMED)

    # 获取匹配结果的位置
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)

    top_left2 = max_loc
    bottom_right2 = (top_left2[0] + template_resize.shape[1], top_left2[1] + template_resize.shape[0])
    # 在输入图像上绘制矩形标记
    cv2.rectangle(image_resize, top_left2, bottom_right2, (0, 0, 255), 2)
    cv2.imwrite('./test/Result' + str(int(time.time())) + '.jpg', image_resize)
    # x位置
    return max_loc[0]

3. 滑动验证码

def solve_geetest_slider(self):
    global resp
    element = self.pageObj.locator(".****") #滑块背景图元素定位
    expect(element).to_be_visible(timeout=100000)
    style = element.get_attribute('style')  #获取滑块背景图地址
    if style:
        start_index = style.find('url("') + 5
        end_index = style.find('")', start_index)
        if start_index != -1 and end_index != -1:
            image_url = style[start_index:end_index]
            print(f"Found background image URL: {image_url}")
            # 下载并保存图片
            resp = requests.get(image_url)
    with open('bg.jpeg', 'wb') as f:
        f.write(resp.content)
    # 滑动图 
    templateEl = self.pageObj.locator(".****").nth(0) #滑块缺块图元素定位
    expect(templateEl).to_be_visible(timeout=100000)

    style = templateEl.get_attribute('style')  #获取滑块缺块图地址
    if style:
        start_index = style.find('url("') + 5
        end_index = style.find('")', start_index)
        if start_index != -1 and end_index != -1:
            image_url = style[start_index:end_index]
            print(f"Found background image URL: {image_url}")
            # 下载并保存图片
            resp = requests.get(image_url)
    with open('template.png', 'wb') as f:
        f.write(resp.content)
    #  获取滑动距离
    image_height = element.bounding_box()["height"]
    image_width = element.bounding_box()["width"]
    template_height = templateEl.bounding_box()["height"]
    template_width = templateEl.bounding_box()["width"]
    print('----------------------------')
    print(image_height, image_width, template_height, template_width)
    x = get_move_x("bg.jpeg", "template.png", image_height, image_width, template_height, template_width)
    # x 加偏移量
    print(x)
    box = self.pageObj.locator(".*****").bounding_box()  #滑道元素定位
    self.pageObj.locator(".geetest_btn").nth(0).hover()  #滑块元素定位
    self.pageObj.mouse.down()
    # 移动鼠标
    start = 1
    end = x + 40
    # 使用贝塞尔曲线生成移动轨迹
    curve_points = generate_bezier_curve(start, end)

    for i, number in enumerate(curve_points):
        target_x = box["x"] + number
        target_y = box["y"] + random.randint(-10, 10)
        # 模拟真实的鼠标移动
        self.pageObj.mouse.move(target_x, target_y, steps=4)
        # 添加随机的时间间隔
        time.sleep(random.uniform(0.05, 0.2))

    # 模拟真实的鼠标悬停和点击
    self.pageObj.mouse.move(box["x"] + end, box["y"] + random.randint(-10, 10), steps=4)
    time.sleep(random.uniform(0.2, 0.5))

    self.pageObj.mouse.up()

代码解释

  1. 生成贝塞尔曲线的坐标点generate_bezier_curve 函数使用 bezier 库生成贝塞尔曲线的坐标点,模拟人类的滑动轨迹。
  2. 计算滑动距离get_move_x 函数使用 OpenCV 库进行模板匹配,找出滑动图在背景图中的位置,从而计算出需要滑动的距离。
  3. 解决极验滑动验证码solve_geetest_slider 函数使用 Playwright 库模拟鼠标的滑动操作,完成验证码的验证。

注意事项

  • 此代码仅用于学习和研究目的,请勿用于非法活动。
  • 极验验证码可能会不断更新和改进,代码可能需要根据实际情况进行调整。
  • 在使用代码时,请确保已经安装了所需的库,如 OpenCVPlaywrightrequests 等

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐