python + selenium通过滑块验证

1、介绍

使用python进行自动化操作或者爬虫过程中,可能会遇到需要进行验证的情况。本文介绍了两种通过滑块验证的方法:

  • 轮廓检测
    • 通过OpenCV进行轮廓检测,找到滑块背景中缺口的位置,计算缺口到滑块的距离。
  • 模板匹配
    • 通过OpenCV分析滑块背景图与滑块的相似度,找到滑块背景图中与滑块最相似的区域就是缺口的位置,然后计算缺口到滑块的距离。

2、轮廓检测

测试地址:https://accounts.douban.com/passport/login

获取滑块背景图

以豆瓣网为例,首先需要获取滑块验证码中的滑块背景图。通过开发者工具分析页面元素,可以看到滑块背景图被放在一个div块中,图片的url被放在div的style属性中。我们可以通过正则表达式将style属性中的图片url提取出来。然后通过request模块将图片保存到本地。
python + selenium通过滑块验证_第1张图片

# 滑块背景
slide_bg_str = driver.find_element(By.ID, 'slideBg').get_attribute("style")
# print(slide_bg_str)
pattern = 'background-image: url\\(\".*?\"\\);'
# 正则表达式提取图片url
slide_bg_url = str(re.findall(pattern, slide_bg_str, re.S)[0]).split('"')[1]
# print(slide_bg_url)
# 通过图片url将图片保存到本地
request.urlretrieve(url=slide_bg_url, filename='./MarkPicture/slide_bg.png')

计算滑块背景图中缺口的位置

这里使用的是轮廓检测算法,具体参考:https://blog.csdn.net/flyfish1986/article/details/147332518
以下是封装的方法:

# 封装的计算图片距离的算法
# imageSrc图片路径,传入滑块背景图的路径,返回缺口的x坐标
def get_pos(imageSrc):
    # 读取图像文件并返回一个image数组表示的图像对象
    image = cv2.imread(imageSrc)
    # GaussianBlur方法进行图像模糊化/降噪操作。
    # 它基于高斯函数(也称为正态分布)创建一个卷积核(或称为滤波器),该卷积核应用于图像上的每个像素点。
    blurred = cv2.GaussianBlur(image, (5, 5), 0, 0)
    # Canny方法进行图像边缘检测
    # image: 输入的单通道灰度图像。
    # threshold1: 第一个阈值,用于边缘链接。一般设置为较小的值。
    # threshold2: 第二个阈值,用于边缘链接和强边缘的筛选。一般设置为较大的值
    canny = cv2.Canny(blurred, 0, 100)  # 轮廓
    # findContours方法用于检测图像中的轮廓,并返回一个包含所有检测到轮廓的列表。
    # contours(可选): 输出的轮廓列表。每个轮廓都表示为一个点集。
    # hierarchy(可选): 输出的轮廓层次结构信息。它描述了轮廓之间的关系,例如父子关系等。
    contours, hierarchy = cv2.findContours(canny, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    # 遍历检测到的所有轮廓的列表
    for contour in contours:
        # contourArea方法用于计算轮廓的面积
        area = cv2.contourArea(contour)
        # arcLength方法用于计算轮廓的周长或弧长
        length = cv2.arcLength(contour, True)
        # 如果检测区域面积在5025-7225之间,周长在300-380之间,则是目标区域 可以根据实际情况进行调整
        if 5025 < area < 7225 and 300 < length < 380:
            # 计算轮廓的边界矩形,得到坐标和宽高
            # x, y: 边界矩形左上角点的坐标。
            # w, h: 边界矩形的宽度和高度。
            x, y, w, h = cv2.boundingRect(contour)
            print("计算出目标区域的坐标及宽高:", x, y, w, h)
            # 在目标区域上画一个红框看看效果
            cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
            cv2.imwrite("./MarkPicture/mark_picture.png", image)
            return x
    return 0

python + selenium通过滑块验证_第2张图片
找到缺口位置后,会标记出来,如上图所示。
这里需要注意的是,因为获取的是源图片,展示在页面中的图片的比例有所变化,所以需要按比例缩放得到的距离:新缺口坐标 = 原缺口坐标 * 新画布宽度 / 原画布宽度

newDis = int(dis * 340 / 672)

获取滑块按钮位置

打开开发者工具,找到滑块按钮所在的div块,右键鼠标,复制元素的XPath。使用selenium通过XPath找到该元素:
python + selenium通过滑块验证_第3张图片

# 滑块按钮
swipe = driver.find_element(By.XPATH, '//*[@id="tcOperation"]/div[6]')
# 滑块按钮的x坐标
swipe_x = swipe.location['x']

计算滑动到滑块按钮的距离,滑动滑块

# 需要下方滑块需要移动的距离
need_move_dis = newDis - swipe_x
ActionChains(driver).click_and_hold(swipe).perform()
step = 0
cur_step = 0
while step < need_move_dis:
	cur_step = random.randint(3, 10)
	step += cur_step
	ActionChains(driver).move_by_offset(xoffset=cur_step, yoffset=0).perform()
ActionChains(driver).release().perform()

完整代码

import re
import random
from selenium import webdriver  # 导入selenium的webdriver模块
from selenium.common import TimeoutException
from selenium.webdriver.common.by import By  # 引入By类选择器
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import urllib.request as request
from selenium.webdriver.common.action_chains import ActionChains  # 动作类
import cv2

driver = webdriver.Edge()

# 封装的计算图片距离的算法
def get_pos(imageSrc):
    # 读取图像文件并返回一个image数组表示的图像对象
    image = cv2.imread(imageSrc)
    # GaussianBlur方法进行图像模糊化/降噪操作。
    # 它基于高斯函数(也称为正态分布)创建一个卷积核(或称为滤波器),该卷积核应用于图像上的每个像素点。
    blurred = cv2.GaussianBlur(image, (5, 5), 0, 0)
    # Canny方法进行图像边缘检测
    # image: 输入的单通道灰度图像。
    # threshold1: 第一个阈值,用于边缘链接。一般设置为较小的值。
    # threshold2: 第二个阈值,用于边缘链接和强边缘的筛选。一般设置为较大的值
    canny = cv2.Canny(blurred, 0, 100)  # 轮廓
    # findContours方法用于检测图像中的轮廓,并返回一个包含所有检测到轮廓的列表。
    # contours(可选): 输出的轮廓列表。每个轮廓都表示为一个点集。
    # hierarchy(可选): 输出的轮廓层次结构信息。它描述了轮廓之间的关系,例如父子关系等。
    contours, hierarchy = cv2.findContours(canny, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    # 遍历检测到的所有轮廓的列表
    for contour in contours:
        # contourArea方法用于计算轮廓的面积
        area = cv2.contourArea(contour)
        # arcLength方法用于计算轮廓的周长或弧长
        length = cv2.arcLength(contour, True)
        # 如果检测区域面积在5025-7225之间,周长在300-380之间,则是目标区域 可以根据实际情况进行调整
        if 5025 < area < 7225 and 300 < length < 380:
            # 计算轮廓的边界矩形,得到坐标和宽高
            # x, y: 边界矩形左上角点的坐标。
            # w, h: 边界矩形的宽度和高度。
            x, y, w, h = cv2.boundingRect(contour)
            print("计算出目标区域的坐标及宽高:", x, y, w, h)
            # 在目标区域上画一个红框看看效果
            cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
            cv2.imwrite("./MarkPicture/mark_picture.png", image)
            return x
    return 0
    
try:
    driver.get("https://accounts.douban.com/passport/login")
    driver.implicitly_wait(2)
    # 切换到密码登录
    driver.find_element(by=By.CLASS_NAME, value="account-tab-account").click()
    print("切换到密码登录")
    driver.find_element(By.ID, 'username').send_keys("18012345678")
    print("输入账号")
    driver.find_element(By.ID, 'password').send_keys("123456")
    print("输入密码")
    driver.find_element(By.CLASS_NAME, 'btn.btn-account.btn-active').click()
    print("点击登录豆瓣")
    # 点击登陆后会弹出滑动验证
    # 滑块验证在一个iframe中,需要将鼠标放入iframe中,不然找不到元素
    driver.switch_to.frame('tcaptcha_iframe_dy')
    try:
        WebDriverWait(driver, 10).until(
            EC.visibility_of_element_located((By.ID, 'slideBg'))
        )
        # 滑块背景
        slide_bg_str = driver.find_element(By.ID, 'slideBg').get_attribute("style")
        # print(slide_bg_str)
        pattern = 'background-image: url\\(\".*?\"\\);'
        slide_bg_url = str(re.findall(pattern, slide_bg_str, re.S)[0]).split('"')[1]
        # print(slide_bg_url)
        request.urlretrieve(url=slide_bg_url, filename='./MarkPicture/slide_bg.png')
        # 找到滑块图片需要补全的部分
        dis = get_pos('./MarkPicture/slide_bg.png')
        # 找到下方滑块按钮
        swipe = driver.find_element(By.XPATH, '//*[@id="tcOperation"]/div[6]')
		swipe_x = swipe.location['x']
        # 下方滑块按钮到目标区域的移动距离(缺口坐标的水平位置距离小滑块的水平坐标相减的差)
        # 新缺口坐标=原缺口坐标*新画布宽度/原画布宽度
        newDis = int(dis * 340 / 672)
        # 需要下方滑块按钮需要移动的距离
        need_move_dis = newDis - swipe_x 
        ActionChains(driver).click_and_hold(swipe).perform()
        step = 0
        cur_step = 0
        while step < need_move_dis:
            cur_step = random.randint(3, 10)
            step += cur_step
            ActionChains(driver).move_by_offset(xoffset=cur_step, yoffset=0).perform()
        ActionChains(driver).release().perform()
    except TimeoutException:
        print("未找到滑动验证")
    time.sleep(3)
finally:
    driver.close()

3、模板匹配

测试地址:https://demos.geetest.com/slide-custom.html
注意:由于极验验证码的安全性太强,此方法仅能做到拖动滑块到缺口,但是这样仍能被极验网站判定为非人为操作,导致验证失败。所以本部分内容仅作为通过滑块验证的方法分享。

获取滑块背景图片

与上面不同,这里的滑块背景在canvas块中,无法通过元素属性获得图片地址,所以采用的方案是截图。
python + selenium通过滑块验证_第4张图片

分析页面中的元素,可以看到滑块验证码中有两个重叠的canvas块,一个是滑块背景图,一个是小滑块。这里的思路是先将小滑块canvas的display属性设置为none,这样将小滑块暂时隐藏,然后截图保存滑块背景图,然后将小滑块canvas的display属性设置为block,这样小滑块就重新展示出来了。
python + selenium通过滑块验证_第5张图片

# 滑块背景
slice_bg = driver.find_element(By.CLASS_NAME, 'geetest_canvas_bg.geetest_absolute')
# 滑块
small_slice = driver.find_element(By.CLASS_NAME, 'geetest_canvas_slice.geetest_absolute')
# 隐藏滑块
driver.execute_script("arguments[0].style.display='none';", small_slice)
# 截取滑块背景
es.element_shot(driver, slice_bg, "./MarkPicture/canvas_slice_bg.png")
# 显示滑块
driver.execute_script("arguments[0].style.display='block';", small_slice)

element_shot(driver: webdriver, element, save_path: str)是重新封装的函数,具体实现如下:

def element_shot(driver: webdriver, element, save_path: str):
    try:
        # 获取元素位置和尺寸
        location = element.location
        size = element.size
        # 获取设备像素比例 (解决高分辨率屏幕缩放问题)
        # device_pixel_ratio = driver.execute_script("return window.devicePixelRatio")
        # 计算实际像素坐标(乘以设备像素比例)
        # x = location['x'] * device_pixel_ratio
        # y = location['y'] * device_pixel_ratio
        # width = size['width'] * device_pixel_ratio
        # height = size['height'] * device_pixel_ratio
        x = location['x']
        y = location['y']
        width = size['width']
        height = size['height']
        # 截取全屏并保存
        driver.save_screenshot('./MarkPicture/temp_screenshot.png')
        # 使用Pillow打开截图并裁剪元素区域
        full_image = Image.open("./MarkPicture/temp_screenshot.png")
        element_image = full_image.crop((
            x,              # 左边界
            y,              # 上边界
            x + width,      # 右边界
            y + height      # 下边界
        )).convert("RGB")
        # 保存元素截图
        element_image.save(save_path, optimize=False, quality=100)
        print(save_path + " 保存成功!!!")
    except Exception as e:
        print(f"截图失败: {e}")

获取滑块图片

同获取滑块背景图片一样的步骤,不过还要多出一步。因为截图的是整个canvas,canvas中滑块只占了一小部分,所以还需要使用轮廓检测算法算出滑块截图中滑块的位置,然后再次截图保存。在截图之前要记得先使用轮廓检测算法找到滑块的位置并记录下来。
python + selenium通过滑块验证_第6张图片

截图保存的这一步可以封装为以下这个函数:

def image_cut_bg(driver: webdriver, imageSrc):
    # 读取图像文件并返回一个image数组表示的图像对象
    image = cv2.imread(imageSrc)
    # 转灰度
    image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # print("imageSrc: " + imageSrc)
    # GaussianBlur方法进行图像模糊化/降噪操作。
    # 它基于高斯函数(也称为正态分布)创建一个卷积核(或称为滤波器),该卷积核应用于图像上的每个像素点。
    blurred = cv2.GaussianBlur(image, (5, 5), 0, 0)
    # Canny方法进行图像边缘检测
    # image: 输入的单通道灰度图像。
    # threshold1: 第一个阈值,用于边缘链接。一般设置为较小的值。
    # threshold2: 第二个阈值,用于边缘链接和强边缘的筛选。一般设置为较大的值
    canny = cv2.Canny(blurred, 100, 200)  # 轮廓
    # findContours方法用于检测图像中的轮廓,并返回一个包含所有检测到轮廓的列表。
    # contours(可选): 输出的轮廓列表。每个轮廓都表示为一个点集。
    # hierarchy(可选): 输出的轮廓层次结构信息。它描述了轮廓之间的关系,例如父子关系等。
    contours, hierarchy = cv2.findContours(canny, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    x = 0
    y = 0
    w = 0
    h = 0
    # 遍历检测到的所有轮廓的列表
    for contour in contours:
        # contourArea方法用于计算轮廓的面积
        area = cv2.contourArea(contour)
        print("area: " + str(area))
        # arcLength方法用于计算轮廓的周长或弧长
        length = cv2.arcLength(contour, True)
        print("length: " + str(length))
        # 如果检测区域面积在5025-7225之间,周长在300-380之间,则是目标区域
        if 1500 < area < 2700 and 140 < length < 280:
            # 计算轮廓的边界矩形,得到坐标和宽高
            # x, y: 边界矩形左上角点的坐标。
            # w, h: 边界矩形的宽度和高度。
            x, y, w, h = cv2.boundingRect(contour)
            print("es 计算出目标区域的坐标及宽高:", x, y, w, h)
            # 在目标区域上画一个红框看看效果
            # cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
            # cv2.imwrite("./MarkPicture/canvas_small_slice.png", image)
    # 使用Pillow打开截图并裁剪元素区域
    full_image = Image.open(imageSrc)
    element_image = full_image.crop((
        x,  # 左边界
        y,  # 上边界
        x + w,  # 右边界
        y + h  # 下边界
    )).convert("RGB")
    # 保存元素截图
    element_image.save(imageSrc, optimize=False, quality=100)
    print("去除背景完成")

对比两张图片,分析相似度得到滑块背景图中缺口的位置

这里主要用的是模板匹配算法,具体参考:OpenCV第十章——模板匹配

# 模板匹配
def detect_captcha_gap(bg, tp):
    """
    bg: 滑块背景图片
    tp: 滑块图片
    return:空缺距背景图左边的距离
    """
    # 读取背景图片和缺口图片
    bg_img = cv2.imread(bg)  # 背景图片
    tp_img = cv2.imread(tp)  # 缺口图片
    # bg_img = bg
    # tp_img = tp
    # 识别图片边缘
    bg_edge = cv2.Canny(bg_img, 200, 300)
    tp_edge = cv2.Canny(tp_img, 300, 350)
    # 转换图片格式
    bg_pic = cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB)
    tp_pic = cv2.cvtColor(tp_edge, cv2.COLOR_GRAY2RGB)
    cv2.imwrite("./MarkPicture/bg_style.png", bg_pic)  # 保存背景轮廓提取
    cv2.imwrite("./MarkPicture/slide_style.png", tp_pic)  # 保存滑块背景提取
    # 缺口匹配
    res = cv2.matchTemplate(bg_pic, tp_pic, cv2.TM_CCOEFF_NORMED)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)  # 寻找最优匹配
    th, tw = tp_pic.shape[:2]
    tl = max_loc  # 左上角点的坐标
    # 返回缺口的左上角X坐标
    br = (tl[0] + tw, tl[1] + th)  # 右下角点的坐标
    cv2.rectangle(bg_img, tl, br, (0, 0, 255), 2)  # 绘制矩形
    cv2.imwrite("./MarkPicture/result_new.png", bg_img)  # 保存在本地
    # 返回缺口的左上角X坐标
    return tl[0]

计算滑块到缺口的距离, 滑动滑块

# 滑块按钮
swipe = driver.find_element(By.CLASS_NAME, 'geetest_slider_button')
ActionChains(driver).click_and_hold(swipe).perform()
step = 0
need_step = dis1 - dis2
cur_step = 0
# 模拟抖动
while step < need_step:
    cur_step = random.randint(-4, 15)
    if step + cur_step > need_step:
        ActionChains(driver).move_by_offset(xoffset=need_step - step + 1, yoffset=random.randint(-5, 7)).perform()
        break
    step += cur_step
    ActionChains(driver).move_by_offset(xoffset=cur_step, yoffset=random.randint(-5, 7)).perform()
ActionChains(driver).release().perform()

完整代码

# 跳过极验滑块验证
import re
import random
from selenium import webdriver  # 导入selenium的webdriver模块
from selenium.common import TimeoutException
from selenium.webdriver.common.by import By  # 引入By类选择器
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import urllib.request as request
from selenium.webdriver.common.action_chains import ActionChains  # 动作类
import cv2
import utils.element_shot as es

# 防止识别出来是selenium
option = webdriver.EdgeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])
# 如何实现让selenium规避被检测的风险
driver = webdriver.Edge(options=option)
script = 'Object.defineProperty(navigator,"webdriver",{get:()=>undefined,});'
driver.execute_script(script)

# 封装的计算图片距离的算法
def get_pos(imageSrc):
    # 读取图像文件并返回一个image数组表示的图像对象
    image = cv2.imread(imageSrc)
    # 转灰度
    image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    print("imageSrc: " + imageSrc)
    # GaussianBlur方法进行图像模糊化/降噪操作。
    # 它基于高斯函数(也称为正态分布)创建一个卷积核(或称为滤波器),该卷积核应用于图像上的每个像素点。
    blurred = cv2.GaussianBlur(image, (5, 5), 0, 0)
    # Canny方法进行图像边缘检测
    # image: 输入的单通道灰度图像。
    # threshold1: 第一个阈值,用于边缘链接。一般设置为较小的值。
    # threshold2: 第二个阈值,用于边缘链接和强边缘的筛选。一般设置为较大的值
    canny = cv2.Canny(blurred, 100, 200)  # 轮廓
    # findContours方法用于检测图像中的轮廓,并返回一个包含所有检测到轮廓的列表。
    # contours(可选): 输出的轮廓列表。每个轮廓都表示为一个点集。
    # hierarchy(可选): 输出的轮廓层次结构信息。它描述了轮廓之间的关系,例如父子关系等。
    contours, hierarchy = cv2.findContours(canny, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    # 遍历检测到的所有轮廓的列表
    for contour in contours:
        # contourArea方法用于计算轮廓的面积
        area = cv2.contourArea(contour)
        print("area: " + str(area))
        # arcLength方法用于计算轮廓的周长或弧长
        length = cv2.arcLength(contour, True)
        print("length: " + str(length))
        # 如果检测区域面积在5025-7225之间,周长在300-380之间,则是目标区域
        if 1500 < area < 2700 and 140 < length < 280:
            # 计算轮廓的边界矩形,得到坐标和宽高
            # x, y: 边界矩形左上角点的坐标。
            # w, h: 边界矩形的宽度和高度。
            x, y, w, h = cv2.boundingRect(contour)
            print("计算出目标区域的坐标及宽高:", x, y, w, h)
            # 在目标区域上画一个红框看看效果
            cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
            cv2.imwrite("./MarkPicture/mark_picture.png", image)
            return x
    return 0

# 模板匹配
def detect_captcha_gap(bg, tp):
    """
    bg: 背景图片
    tp: 缺口图片
    return:空缺距背景图左边的距离
    """
    # 读取背景图片和缺口图片
    bg_img = cv2.imread(bg)  # 背景图片
    tp_img = cv2.imread(tp)  # 缺口图片
    # bg_img = bg
    # tp_img = tp
    # 识别图片边缘
    bg_edge = cv2.Canny(bg_img, 200, 300)
    tp_edge = cv2.Canny(tp_img, 300, 350)
    # 转换图片格式
    bg_pic = cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB)
    tp_pic = cv2.cvtColor(tp_edge, cv2.COLOR_GRAY2RGB)
    cv2.imwrite("./MarkPicture/bg_style.png", bg_pic)  # 保存背景轮廓提取
    cv2.imwrite("./MarkPicture/slide_style.png", tp_pic)  # 保存滑块背景提取
    # 缺口匹配
    res = cv2.matchTemplate(bg_pic, tp_pic, cv2.TM_CCOEFF_NORMED)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)  # 寻找最优匹配
    th, tw = tp_pic.shape[:2]
    tl = max_loc  # 左上角点的坐标
    # 返回缺口的左上角X坐标
    br = (tl[0] + tw, tl[1] + th)  # 右下角点的坐标
    cv2.rectangle(bg_img, tl, br, (0, 0, 255), 2)  # 绘制矩形
    cv2.imwrite("./MarkPicture/result_new.png", bg_img)  # 保存在本地
    # 返回缺口的左上角X坐标
    return tl[0]

try:
    driver.get("https://demos.geetest.com/slide-custom.html")
    button = driver.find_element(By.ID, 'captcha')
    time.sleep(2)
    button.click()
    WebDriverWait(driver, 10).until(
        EC.visibility_of_element_located((By.CLASS_NAME, 'geetest_canvas_bg.geetest_absolute'))
    )
    print("找到滑块背景")
    slice_bg = driver.find_element(By.CLASS_NAME, 'geetest_canvas_bg.geetest_absolute')

    small_slice = driver.find_element(By.CLASS_NAME, 'geetest_canvas_slice.geetest_absolute')
    # small_slice.__setattr__("style", 'display: none;')
    # 隐藏小滑块
    driver.execute_script("arguments[0].style.display='none';", small_slice)
    time.sleep(1)
    # 截取滑块背景
    es.element_shot(driver, slice_bg, "./MarkPicture/canvas_slice_bg.png")
    # dis1 = get_pos('./MarkPicture/canvas_slice_bg.png')
    # 显示小滑块
    driver.execute_script("arguments[0].style.display='block';", small_slice)
    # 隐藏滑块背景
    driver.execute_script("arguments[0].style.display='none';", slice_bg)
    time.sleep(1)
    # 截取小滑块
    es.element_shot(driver, small_slice, "./MarkPicture/canvas_small_slice.png")
    dis2 = get_pos('./MarkPicture/canvas_small_slice.png')
    # dis2 = 3
    print("dis2: " + str(dis2))

    # 去掉白色背景
    es.image_cut_bg(driver, "./MarkPicture/canvas_small_slice.png")
    # 显示滑块背景
    driver.execute_script("arguments[0].style.display='block';", slice_bg)
    dis1 = detect_captcha_gap("./MarkPicture/canvas_slice_bg.png", "./MarkPicture/canvas_small_slice.png")
    print("dis1: " + str(dis1))
    swipe = driver.find_element(By.CLASS_NAME, 'geetest_slider_button')
    ActionChains(driver).click_and_hold(swipe).perform()
    step = 0
    need_step = dis1 - dis2
    cur_step = 0
    while step < need_step:
        cur_step = random.randint(-4, 15)
        if step + cur_step > need_step:
            ActionChains(driver).move_by_offset(xoffset=need_step - step + 1, yoffset=random.randint(-5, 7)).perform()
            break
        step += cur_step
        ActionChains(driver).move_by_offset(xoffset=cur_step, yoffset=random.randint(-5, 7)).perform()
    ActionChains(driver).release().perform()
except TimeoutException:
    print("未找到滑块验证")
finally:
    time.sleep(3)
    driver.close()

参考文章

  1. 【Python从入门到进阶】39、使用Selenium自动验证滑块登录
  2. python 模板匹配图片识别点击
  3. OpenCV 边缘检测(Edge Detection)cv2.Canny
  4. OpenCV第十章——模板匹配

你可能感兴趣的:(python,selenium,爬虫,opencv)