zoukankan      html  css  js  c++  java
  • python+selenium破解极验验证登录

    1、前言:

      目前很多网站会在正常的账号密码认证之外加一些验证码,以此来明确区分人/机行为,最典型的就是极验滑动验证。(如下图)

    这里我们以简单实例说明如何实现自动校验类似验证。

    2、步骤:

    1)点击验证,弹出验证码图片;

    2)操作JS,获取完整验证码图片并截图;

    3)操作JS恢复原图,获取带有缺口的验证码图片并截图;

    4)对比两张图片所有的像素点,得到要移动的距离;

    5)模拟人的行为,把需要拖动的总距离分成一段一段的轨迹;

    6)按照轨迹拖动,完成验证;

    7)完成登录;

    3、准备工作:

    1)安装chrome浏览器;

    2)配置好python+selenium环境;

    3)安装Pillow模块;

    4、详细代码:

    from selenium import webdriver
    from selenium.webdriver import ActionChains  # 破解滑动验证码的时候用的 可以拖动图片
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from PIL import Image
    from io import BytesIO
    import time
    
    class AccessCode(object):
        def __init__(self,driver):
            self.driver = driver
            self.wait = WebDriverWait(driver, 20)
            self.border = 6 #设置偏差值
        def get_position(self):
            """
            获取验证码位置
            :return: 验证码位置元组
            """
            img = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'geetest_window')))
            time.sleep(2)
            location = img.location
            size = img.size
            top, bottom, left, right = location['y'], location['y'] + size['height'], location['x'], location['x'] + size['width']
            return (top, bottom, left, right)
    
        def get_screenshot(self):
            """
            获取网页截图
            :return: 截图对象
            """
            screenshot = self.driver.get_screenshot_as_png()
            screenshot = Image.open(BytesIO(screenshot))
            return screenshot
    
        def get_image1(self,filename):
            '''
            获取完整验证码图片
            :return: 图片对象
            '''
            time.sleep(0.2)
            js_code = '''document.getElementsByClassName('geetest_canvas_fullbg')[0].style.display="block";'''
            time.sleep(1)
            self.driver.execute_script(js_code)
            # 截取图片
            top, bottom, left, right = self.get_position()
            screenshot = self.get_screenshot()
            captcha = screenshot.crop((2 * left, 2 * top, 2 * right, 2 * bottom))
            size = 258, 159
            captcha.thumbnail(size)  # 生成缩略图
            captcha.save(filename)
            return captcha
    
        def get_image2(self,filename):
            '''
            获取有缺口的验证码图片
            :param filename: 图片名称
            :return: 有缺口的验证码图片对象
            '''
            time.sleep(0.2)
            js_code = '''document.getElementsByClassName('geetest_canvas_fullbg')[0].style.display="none";'''
            self.driver.execute_script(js_code)
            time.sleep(1)
            # 截取图片
            top, bottom, left, right = self.get_position()
            screenshot = self.get_screenshot()
            captcha = screenshot.crop((2*left, 2*top, 2*right, 2*bottom))
            size = 258, 159
            captcha.thumbnail(size)  # 生成缩略图
            captcha.save(filename)
            return captcha
    
        def get_gap(self,image1, image2):
            """
            获取缺口偏移量
            :param img1: 不带缺口图片
            :param img2: 带缺口图片
            :return:缺口偏移量
            """
            left = 60
            for i in range(left, image1.size[0]):
                for j in range(image1.size[1]):
                    if not self.is_pixel_equal(image1, image2, i, j):
                        left = i
                        return left
            return left
    
        def is_pixel_equal(self,img1, img2, x, y):
            """
            判断两个像素是否相同
            :param image1: 图片1
            :param image2: 图片2
            :param x: 位置x
            :param y: 位置y
            :return: 像素是否相同
            """
            # 取两个图片的像素点
            pixel1 = img1.getpixel((x, y))
            pixel2 = img2.getpixel((x, y))
    
            for i in range(0, 3):
                if abs(pixel1[i] - pixel2[i]) >= 60:
                    return False
            return True
    
        def get_track(self,distance):
            """
            根据偏移量获取移动轨迹
            :param distance: 偏移量
            :return: 移动轨迹
            """
            # 移动轨迹
            track = []
            # 当前位移
            current = 0
            # 减速阈值
            mid = distance * 4 / 5
            # 计算间隔
            t = 0.2
            # 初速度
            v = 0
            while current < distance:
                if current < mid:
                    # 加速度为正2
                    a = 2
                else:
                    # 加速度为负3
                    a = -3
                # 初速度v0
                v0 = v
                # 当前速度v = v0 + at
                v = v0 + a * t
                # 移动距离x = v0t + 1/2 * a * t^2
                move = v0 * t + 1 / 2 * a * t * t
                # 当前位移
                current += move
                # 加入轨迹
                track.append(round(move))
            return track
    
        def move_to_gap(self,slider, track):
            """
            拖动滑块到缺口处
            :param slider: 滑块
            :param track: 轨迹
            :return:
            """
            ActionChains(self.driver).click_and_hold(slider).perform()
            for x in track:
                ActionChains(self.driver).move_by_offset(xoffset=x, yoffset=0).perform()
            time.sleep(1)
            ActionChains(self.driver).release().perform()
    
        def get_slider(self):
            """
            获取滑块
            :return: 滑块对象
            """
            slider = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_slider_button')))
            return slider
    
    
        def crack(self):
            '''验证操作'''
            #1.针对完整的图片进行截取
            image1 = self.get_image1('snap_full.png')
            #2.针对有缺口的图片进行截取
            image2 = self.get_image2('snap.png')
            #3.对比两张图片,获取滑动距离
            distance = self.get_gap(image1,image2)
            #4减去缺口位移
            distance -= self.border
            #5.获取滑块对象
            slider = self.get_slider()
            #6.模拟人为滑动轨迹
            track = self.get_track(distance)
            #7.拖动滑块
            self.move_to_gap(slider, track)
            time.sleep(5)
            #8.失败重试
            try:
                geetest_class = self.driver.find_element_by_xpath("//div[@class='geetest_panel geetest_wind']/div[2]").get_attribute("class")
                if "geetest_panel_box" == geetest_class:
                    self.driver.find_element_by_xpath("//div[@class='geetest_panel_error_content']").click()
                    self.crack()
                elif "geetest_panelshowslide geetest_shake" in geetest_class:
                    time.sleep(3)
                    self.crack()
            except Exception as e:
                print("------------登录成功--------------")
    
    if __name__ == '__main__':
        import os
        BasePath = os.path.dirname(os.path.abspath(__file__))
        DRIVER_PATH=os.path.join(BasePath,'conf/chromedriver')
        chrome_options = webdriver.ChromeOptions()
        chrome_options.add_argument('--start-maximized')  # 指定浏览器分辨率
        chrome_options.add_argument('--disable-gpu')  # 谷歌文档提到需要加上这个属性来规避bug
        driver = webdriver.Chrome(executable_path=DRIVER_PATH, options=chrome_options) #DRIVER_PATH为chromedriver存放路径,自行变更
        crack = AccessCode(driver)
        # 1.打开网页
        driver.get("https://passport.cnblogs.com/user/signin")
        driver.maximize_window() #窗口最大化
        # 2.输入用户名,username自行补全
        driver.find_element_by_xpath("//input[@id='mat-input-0']").send_keys(username)
        # 3.输入密码,password自行补全
        driver.find_element_by_xpath("//input[@id='mat-input-1']").send_keys(password)
        # 4.点击登录,弹出验证按钮
        driver.find_element_by_xpath("//button[@class='mat-focus-indicator action-button ng-tns-c141-2 mat-flat-button mat-button-base mat-primary']").click()
        # 5.点击验证按钮
        time.sleep(3)
        # 6.调用验证
        crack.crack()
    

      

  • 相关阅读:
    单调栈
    【算法】验证码识别基础方法及源码
    获取安全时间
    用Cecil任意修改.Net程序集+源码
    【C#】纯托管实现一个Git服务端
    一个普通的但难以作答的面试题
    【WP7】欺骗你的地理坐标+源码
    【WP7】判断GPS坐标是否在中国
    完美的web 2.0站点用户中心标准,及开源用户中心nUserCenter进展报告
    开源 Asp.net mvc 用户中心开发计划
  • 原文地址:https://www.cnblogs.com/cocc/p/10820359.html
Copyright © 2011-2022 走看看