1. 程式人生 > >利用selenium庫自動執行滑動驗證碼模擬登陸

利用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('[email protected]')
        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()