python-selenium-how-to-geetest-slide

利用Python-Selenium破解极验证滑块

头像
逆旅 2022-08-04T17:22:02

1.前言

请准备好:

2.流程逻辑

st=>start: 访问网页 op1=>operation: 点击验证 op2=>operation: 获取滑块图片 op3=>operation: 计算位移 op4=>operation: 模拟人工滑动 cond=>condition: 验证成功 Yes or No? e=>end: 完成任务 st->op1->op2->op3->op4->cond cond(yes)->e cond(no)->op2

3.具体程序

3.1获取图片

一张为原图,另一张为有滑块的图
不含滑块原图
不含滑块原图
含滑块图片
含滑块图片

def get_image(browser, wait):
    """
    获取图片截图
    bg.png==>原始图片
    fullbg.png==>无滑块图片
    """
    button = wait.until(
        EC.presence_of_element_located(
            (By.XPATH,
             '/html/body/form/div[3]/div/div[3]/div[2]/div[1]/div[3]')))
    button.click()
    geetest_canvas_bg = wait.until(
        EC.presence_of_element_located((By.CLASS_NAME, 'geetest_canvas_bg')))
    time.sleep(0.5)
    js = 'var change = document.getElementsByClassName("geetest_canvas_slice");change[0].style = "display: none;"'
    browser.execute_script(js)
    geetest_canvas_bg.screenshot('bg.png')

    js = 'var change1 = document.getElementsByClassName("geetest_canvas_fullbg");change1[0].style = "display: block;"'
    browser.execute_script(js)
    time.sleep(0.5)
    geetest_canvas_fullbg = wait.until(
        EC.presence_of_element_located((By.CLASS_NAME, 'geetest_canvas_bg')))
    geetest_canvas_fullbg.screenshot('fullbg.png')
    image_bg = Image.open('bg.png')
    image_fullbg = Image.open('fullbg.png')
    js = 'var change = document.getElementsByClassName("geetest_canvas_slice");change[0].style = "display: block;"'
    browser.execute_script(js)
    return image_bg, image_fullbg

browser.execute_script()注入js,让滑块消失

3.2比较图片,计算位移

方法一:

def get_diff_location(image1, image2):
    '''
    通过像素对比 找到缺口位置
    :param image1:
    :param image2:
    :return:
    '''
    for x in range(60, image1.size[0]):
        for y in range(1, image2.size[1]):
            if is_similar(image1, image2, x, y) == False:
                # 判断成立 表示xy这个点 两张图的像素点是不一样的
                return x


def is_similar(image1, image2, x, y):
    '''
    找两个像素点不同之处
    '''
    pixel1 = image1.getpixel((x, y))
    pixel2 = image2.getpixel((x, y))  # 元组

    for i in range(0, 3):
        if abs(pixel1[i] - pixel2[i]) >= 50:
            return False

    return True

方法二:

def get_gap(image1, image2):
    """
    获取缺口偏移量
    :param image1: 带缺口图片
    :param image2: 不带缺口图片
    :return:
    """
    left = 60
    print(image1.size[0])
    print(image1.size[1])
    for i in range(left, image1.size[0]):
        for j in range(image1.size[1]):
            if not is_pixel_equal(image1, image2, i, j):
                left = i
                return left
    return left


def is_pixel_equal(image1, image2, x, y):
    """
    判断两个像素是否相同
    :param image1: 图片1
    :param image2: 图片2
    :param x: 位置x
    :param y: 位置y
    :return: 像素是否相同
    """
    # 取两个图片的像素点
    pixel1 = image1.load()[x, y]
    pixel2 = image2.load()[x, y]
    threshold = 60
    if abs(pixel1[0] - pixel2[0]) < threshold and abs(
            pixel1[1] - pixel2[1]) < threshold and abs(pixel1[2] -
                                                       pixel2[2]) < threshold:
        return True
    else:
        return False

3.3模拟人工滑动

我的思路:快速滑动(20),慢慢滑动略微超过(10-5),慢慢返回(-1)

def get_tracks(x: int):
    tracks = [0, 0]
    num = 0
    while num + 20 < x:
        num += 20
        tracks.append(20)
    while num + 10 < x:
        num += 10
        tracks.append(10)
    while num + 5 < x:
        num += 5
        tracks.append(5)
    while num + 3 < x:
        num += 3
        tracks.append(3)
    for i in range((x - num) + 2):
        tracks.append(1)
    tracks.append(-1)
    tracks.append(-1)
    return tracks

注意:由于滑块有初始位移,计算时要根据情况减去

3.4主程序

def Geetest(url, path):
    browser = webdriver.Firefox(executable_path=path)
    browser.maximize_window()
    browser.get(url)
    wait = WebDriverWait(browser, 10)
    image_bg, image_fullbg = get_image(browser, wait)
    x = get_diff_location(image_bg, image_fullbg)
    print('偏移距离:' + str(x))
    tracks = get_tracks(x - 5)
    elem = wait.until(
        EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_slider_button')))
    ActionChains(browser).click_and_hold(elem).perform()
    for track in tracks:
        ActionChains(browser).move_by_offset(xoffset=track,
                                             yoffset=0).perform()
    time.sleep(1)
    ActionChains(browser).release(elem).perform()

4.完整程序&&成果

from os import path
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
import time
from PIL import Image


def get_image(browser, wait):
    """
    获取图片截图
    bg.png==>原始图片
    fullbg.png==>无滑块图片
    """
    button = wait.until(
        EC.presence_of_element_located(
            (By.XPATH,
             '/html/body/form/div[3]/div/div[3]/div[2]/div[1]/div[3]')))
    button.click()
    geetest_canvas_bg = wait.until(
        EC.presence_of_element_located((By.CLASS_NAME, 'geetest_canvas_bg')))
    time.sleep(0.5)
    js = 'var change = document.getElementsByClassName("geetest_canvas_slice");change[0].style = "display: none;"'
    browser.execute_script(js)
    geetest_canvas_bg.screenshot('bg.png')

    js = 'var change1 = document.getElementsByClassName("geetest_canvas_fullbg");change1[0].style = "display: block;"'
    browser.execute_script(js)
    time.sleep(0.5)
    geetest_canvas_fullbg = wait.until(
        EC.presence_of_element_located((By.CLASS_NAME, 'geetest_canvas_bg')))
    geetest_canvas_fullbg.screenshot('fullbg.png')
    image_bg = Image.open('bg.png')
    image_fullbg = Image.open('fullbg.png')
    js = 'var change = document.getElementsByClassName("geetest_canvas_slice");change[0].style = "display: block;"'
    browser.execute_script(js)
    return image_bg, image_fullbg


def get_diff_location(image1, image2):
    '''
    通过像素对比 找到缺口位置
    :param image1:
    :param image2:
    :return:
    '''
    for x in range(60, image1.size[0]):
        for y in range(1, image2.size[1]):
            if is_similar(image1, image2, x, y) == False:
                # 判断成立 表示xy这个点 两张图的像素点是不一样的
                return x


def is_similar(image1, image2, x, y):
    '''
    找两个像素点不同之处
    '''
    pixel1 = image1.getpixel((x, y))
    pixel2 = image2.getpixel((x, y))  # 元组

    for i in range(0, 3):
        if abs(pixel1[i] - pixel2[i]) >= 50:
            return False

    return True


def get_tracks(x: int):
    tracks = [0, 0]
    num = 0
    while num + 20 < x:
        num += 20
        tracks.append(20)
    while num + 10 < x:
        num += 10
        tracks.append(10)
    while num + 5 < x:
        num += 5
        tracks.append(5)
    while num + 3 < x:
        num += 3
        tracks.append(3)
    for i in range((x - num) + 2):
        tracks.append(1)
    tracks.append(-1)
    tracks.append(-1)
    return tracks


def get_gap(image1, image2):
    """
    获取缺口偏移量
    :param image1: 带缺口图片
    :param image2: 不带缺口图片
    :return:
    """
    left = 60
    print(image1.size[0])
    print(image1.size[1])
    for i in range(left, image1.size[0]):
        for j in range(image1.size[1]):
            if not is_pixel_equal(image1, image2, i, j):
                left = i
                return left
    return left


def is_pixel_equal(image1, image2, x, y):
    """
    判断两个像素是否相同
    :param image1: 图片1
    :param image2: 图片2
    :param x: 位置x
    :param y: 位置y
    :return: 像素是否相同
    """
    # 取两个图片的像素点
    pixel1 = image1.load()[x, y]
    pixel2 = image2.load()[x, y]
    threshold = 60
    if abs(pixel1[0] - pixel2[0]) < threshold and abs(
            pixel1[1] - pixel2[1]) < threshold and abs(pixel1[2] -
                                                       pixel2[2]) < threshold:
        return True
    else:
        return False


def Geetest(url, path):
    browser = webdriver.Firefox(executable_path=path)
    browser.maximize_window()
    browser.get(url)
    wait = WebDriverWait(browser, 10)
    image_bg, image_fullbg = get_image(browser, wait)
    x = get_diff_location(image_bg, image_fullbg)
    print('偏移距离:' + str(x))
    tracks = get_tracks(x - 5)
    elem = wait.until(
        EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_slider_button')))
    ActionChains(browser).click_and_hold(elem).perform()
    for track in tracks:
        ActionChains(browser).move_by_offset(xoffset=track,
                                             yoffset=0).perform()
    time.sleep(1)
    ActionChains(browser).release(elem).perform()


if __name__ == '__main__':
    path = '/Volumes/数据/program/python/spider/geckodriver'
    url = 'https://www.geetest.com/demo/slide-custom.html'
    Geetest(url, path)

破解极验证滑动验证

5.参考

python+selenium极验滑动验证码的实现

b站滑动登陆

最后修改: 2022-08-04T17:22:02

版权声明:署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)

comment 评论

验证图片
评论
头像
2023-09-03T11:45:16 回复

好啊

仿 Valine