python识别滑块验证码captcha并自动登录


识别滑块验证码并自动登录

import cv2
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains
from urllib.request import urlretrieve
from time import sleep


# 初始化
def init():
    # 定义为全局变量,方便其他模块使用
    global url, browser, username, password, wait
    # 登录界面的url
    url = 'https://login.ouyeel.com/sso/login?service=https://www.ouyeel56.com/ttp/wl_index/index.jsp'
    # 实例化一个chrome浏览器
    browser = webdriver.Chrome()
    # 设置等待超时
    wait = WebDriverWait(browser, 20)


# 登录
def input_username_password(username, password):
    # 打开登录页面
    browser.get(url)
    # 获取用户名输入框
    user = wait.until(EC.presence_of_element_located(
        (By.XPATH, '//*[@placeholder="T代码/N代码"]')))
    # 获取密码输入框
    passwd = wait.until(
        EC.presence_of_element_located((By.XPATH, '//*[@placeholder="账号密码"]')))
    # 账户登录tab
    logintab = wait.until(
        EC.presence_of_element_located((By.XPATH, '//*[@id="tab-accountLogin"]')))
    # 登录
    login = wait.until(
        EC.presence_of_element_located((By.XPATH, '//*[@id="pane-accountLogin"]/form/div[@class="el-form-item login-submit"]')))
    # 点击logintab
    logintab.click()
    # 输入用户名
    user.send_keys(username)
    # 输入密码
    passwd.send_keys(password)
    # 点击登录
    login.click()
    sleep(1)


# 获取滑块距离
def get_distance(bg_img, tp_img, mark_img):
    '''
    bg: 背景图片
    tp: 缺口图片
    out:输出图片
    '''
    # 读取背景图片和缺口图片
    bg_img = cv2.imread(bg_img)  # 背景图片
    tp_img = cv2.imread(tp_img)  # 缺口图片

    # 识别图片边缘
    bg_edge = cv2.Canny(bg_img, 100, 200)
    tp_edge = cv2.Canny(tp_img, 100, 200)

    # 转换图片格式
    bg_pic = cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB)
    tp_pic = cv2.cvtColor(tp_edge, cv2.COLOR_GRAY2RGB)

    # 缺口匹配
    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  # 左上角点的坐标
    br = (tl[0]+tw, tl[1]+th)  # 右下角点的坐标
    cv2.rectangle(bg_img, tl, br, (0, 0, 255), 2)  # 绘制矩形
    cv2.imwrite(mark_img, bg_img)  # 保存在本地
    # 返回缺口的X坐标
    distance = tl[0]*2/3
    # print('原来:', tl[0])
    # print('真实:', distance)
    return distance


def move_to_gap(distance):
    # 得到滑块标签
    slider = wait.until(EC.presence_of_element_located(
        (By.XPATH, '//*[@class="yidun_slider"]')))
    # 使用click_and_hold()方法悬停在滑块上,perform()方法用于执行
    ActionChains(browser).click_and_hold(slider).perform()
    # 使用move_by_offset()方法拖动滑块,perform()方法用于执行
    ActionChains(browser).move_by_offset(xoffset=distance, yoffset=0).perform()
    # 模拟人类对准时间
    sleep(0.5)
    # 释放滑块
    ActionChains(browser).release().perform()


# 主程序
def login(username, password, username_sec):
    # 初始化
    init()
    # 登录
    input_username_password(username, password)
    # 处理滑块,循环知道成功
    captcha_sucess = 0
    while not captcha_sucess:
        # 多次失败遭拦截,重新获取验证图片
        try:
            fail = browser.find_element_by_xpath(
                '//*[@class="yidun_tips__text yidun-fallback__tip"]')
            fail.click()
            sleep(1)
        except:
            pass
        sleep(1)
        # 获取img对应src
        bg_image_url = browser.find_element_by_xpath(
            '//*[@alt="验证码背景"]').get_attribute('src')
        tp_image_url = browser.find_element_by_xpath(
            '//*[@alt="验证码滑块"]').get_attribute('src')
        # 使用urlretrieve()方法根据url下载缺口图片对象
        urlretrieve(url=bg_image_url, filename='bg_image.jpg')
        urlretrieve(url=tp_image_url, filename='tp_image.jpg')
        # 获取滑块距离
        distance = get_distance(
            'bg_image.jpg', 'tp_image.jpg', 'mark.jpg')
        # 移动滑块
        move_to_gap(distance+12)
        sleep(1)
        # 判断是否成功
        try:
            hhcscys011 = browser.find_element_by_xpath(
                '//*[text()="{}"]'.format(username_sec))
            print(hhcscys011)
            captcha_sucess = 1
            print("滑块验证成功")
        except:
            pass


# 程序入口
if __name__ == '__main__':
    login('username', 'password', 'username_sec')

 参考文章:

主体:https://blog.csdn.net/Jeeson_Z/article/details/82047685

识别缺口找到滑块距离:https://blog.csdn.net/zhangzeyuaaa/article/details/119508407