利用selenium库自动执行滑动验证码模拟登陆

破解流程

#1、输入账号、密码,然后点击登陆
#2、点击按钮,弹出没有缺口的图
#3、针对没有缺口的图片进行截图
#4、点击滑动按钮,弹出有缺口的图
#5、针对有缺口的图片进行截图
#6、对比两张图片,找出缺口,即滑动的位移
#7、按照人的行为行为习惯,把总位移切成一段段小的位移
#8、按照位移移动
#9、完成登录

模拟登陆案例一:

from selenium import webdriver
from selenium.webdriver import ActionChains
from PIL import Image
import time
import random
option = webdriver.ChromeOptions()
# 添加启动参数 (add_argument)
option.add_argument('disable-infobars')  # 禁用浏览器正在被自动化程序控制的提示

driver = webdriver.Chrome(chrome_options=option)


def get_snap(driver):
    # selenium自带的截图网页全屏图片
    driver.save_screenshot('snap.png')
    # 拿到验证图片所在的标签,方便确认位置
    img = driver.find_element_by_class_name('geetest_canvas_img')
    # location 代表该图片在整个页面所在的位置(x, y),x:距离左边多长,y:距离上面多长
    # print(img.location)
    # size 代表该图片的大小
    # print(img.size)

    left = img.location.get('x')
    upper = img.location.get('y')

    right = left + img.size.get('width')
    lower = upper + img.size.get('height')

    # 拿到图片四个边的位置,就可以进行裁剪图片了
    # print(left, upper, right, lower)
    img_obj = Image.open('snap.png')

    # 对屏幕进行裁剪,获取滑动验证码图片
    image = img_obj.crop((left, upper, right, lower))
    # image.show()

    return image

# 获取完整图片
def get_img1(driver):
    time.sleep(0.2)
    js_code = """
        var x = document.getElementsByClassName('geetest_canvas_fullbg')[0].style.display="block";
        console.log(x)
    """

    # 执行js代码
    driver.execute_script(js_code)
    time.sleep(1)
    # 截取图片
    img_obj = get_snap(driver)

    return img_obj

# 获取有缺口的图片
def get_img2(driver):
    time.sleep(0.2)
    js_code = """
        var x = document.getElementsByClassName('geetest_canvas_fullbg')[0].style.display="none";
        console.log(x)
    """

    # 执行js代码
    driver.execute_script(js_code)
    time.sleep(1)
    # 截取图片
    img_obj = get_snap(driver)

    return img_obj


def get_distance(img1, img2):
    # 初始值
    start = 60

    # 模块色差
    color_num = 60
    for x in range(start, img1.size[0]):
        for y in range(img1.size[1]):
            rgb1 = img1.load()[x, y]
            rgb2 = img2.load()[x, y]

            # abs 获取绝对值
            r = abs(rgb1[0] - rgb2[0])
            g = abs(rgb1[1] - rgb2[1])
            b = abs(rgb1[2] - rgb2[2])

            if not (r < color_num and g < color_num and b < color_num):
                return x - 7  # 误差值大概为7



def get_stacks(distance):
    distance += 20
    '''
        拿到移动轨迹,模仿人的滑动行为,先匀加速后匀减速
        变速运动基本公式:
        ① v=v0+at       匀加速\减速运行
        ② s=v0t+½at²    位移
        ③ v²-v0²=2as    
     '''
    # 初速度
    v0 = 0

    # 加减速度列表
    a_list = [50, 65, 80]

    # 时间
    t = 0.2

    # 初始位置
    s = 0

    # 向前滑动轨迹
    forward_stacks = []

    mid = distance * 3 / 5

    while s < distance:

        if s < mid:
            a = a_list[random.randint(0, 2)]

        else:
            a = -a_list[random.randint(0, 2)]

        v = v0

        stack = v * t + 0.5 * a * (t ** 2)

        # 每次拿到的位移
        stack = round(stack)

        s += stack

        v0 = v + a * t

        forward_stacks.append(stack)

    # 往后返回20距离,因为之前distance向前多走了20
    back_stacks = [-5, -5, -5, -5,]

    return {'forward_stacks': forward_stacks, 'back_stacks': back_stacks}


if __name__ == '__main__':
    try:
        driver.get('https://account.cnblogs.com/signin')
        # 隐式等待
        driver.implicitly_wait(5)

        # 步骤一:找到输入账户框
        user_input = driver.find_element_by_id('LoginName')

        # 步骤二:找到输入密码框
        pwd_input = driver.find_element_by_id('Password')

        user_input.send_keys('123456@qq.com')
        time.sleep(1)
        pwd_input.send_keys('123456')
        # 步骤三:找到确认登录按钮,并点击
        login_btn = driver.find_element_by_id('submitBtn')
        time.sleep(1)
        login_btn.click()
        time.sleep(3)

        # 步骤四: 拿到没有缺口的图片并截取
        img1 = get_img1(driver)

        # 步骤五: 拿到有缺口的图片并截取
        img2 = get_img2(driver)

        # 步骤六: 对比两张图片,获取滑动距离
        distance = get_distance(img1, img2)

        # 步骤七: 模拟人为滑动轨迹
        stacks = get_stacks(distance)

        # 步骤八: 根据滑动轨迹进行滑动
        forward_stacks = stacks['forward_stacks']
        back_stacks = stacks['back_stacks']

        # 步骤九:找到滑动按钮,并点击与hole住
        slider_btn = driver.find_element_by_class_name('geetest_slider_button')
        time.sleep(0.2)
        ActionChains(driver).click_and_hold(slider_btn).perform()
        time.sleep(0.2)

        # 步骤十:开始循环向前滑动
        for forward_stack in forward_stacks:
            ActionChains(driver).move_by_offset(xoffset=forward_stack, yoffset=0).perform()
            time.sleep(0.1)
        # 步骤十一:开始循环向后滑动20
        for back_stack in back_stacks:
            ActionChains(driver).move_by_offset(xoffset=back_stack, yoffset=0).perform()
            time.sleep(0.1)

        time.sleep(0.2)


        # 步骤十二:为了防止极验检测到,再将滑块前后小浮动5位置,再释放

        ActionChains(driver).move_by_offset(xoffset=5, yoffset=0).perform()
        time.sleep(0.2)
        ActionChains(driver).move_by_offset(xoffset=-5, yoffset=0).perform()

        # 可能会出现识别不了,说图片被怪物吃了,上面模拟人的行为都不要了,拿到距离后,直接执行下面代码,一步滑到缺口处即可
        # ActionChains(driver).move_by_offset(xoffset=distance, yoffset=0).perform()

        ActionChains(driver).release().perform()

        time.sleep(50)

    finally:
        driver.close()
posted @ 2020-01-05 00:06  tomjoy  阅读(1296)  评论(1编辑  收藏  举报