zoukankan      html  css  js  c++  java
  • 滑块验证码——以哔哩哔哩为例的滑块验证码破解

    原文:https://www.cnblogs.com/rrh4869/p/11192297.html

    1.模拟登录的网站:

    bilibili视频网:https://passport.bilibili.com/login

    2. 开发环境

    本项目需要用到

    io

    time

    random

    selenium

    PIL

    请安装对应版本的库如下,其他库均为标准库,无需安装 ​ pip install pillow ​ pip install selenium

     

    3.项目流程介绍

    1. 初始化
    2. 请求bilibili的登录页面&模拟输入账号密码
    3. 有阴影拼图的验证码图片&获取验证码图片
    4. 比较两个验证码图片获取验证码滑块的偏移量
    5. 使用偏移值计算移动操作
    6. 操作滑块按钮,模拟拖动滑块做验证登录

    5.bilibili模拟登陆-初始化和模拟输入账号密码

    class Bilibili(object):
    
    	def __init__(self):
    		#创建浏览器对象
    		self.driver = webdriver.Chrome()
    		#隐式等待
    		self.driver.implicitly_wait(3)
    		self.url = 'https://passport.bilibili.com/login'
    		#用户名
    		self.user = ''
    		#密码
    		self.pwd = ''
    
    	def close(self):
    		'''
    		关闭浏览器
    		'''
    		self.driver.quit()
    
    	def input_user_pwd(self):
    		'''
    		   输入用户名和密码
    		'''
    		#进入登陆页面
    		self.driver.get(self.url)
    
    		#文本框输入用户名
    		tb_user = self.driver.find_element_by_id('login-username')
    		tb_user.send_keys(self.user)
    		#文本框输入密码
    		tb_pwd = self.driver.find_element_by_id('login-passwd')
    		tb_pwd.send_keys(self.pwd)

    6.有阴影拼图的验证码图片&获取验证码图片

        def get_screenshot(self):
            '''
            获取屏幕截图
            '''
            screenshot = self.driver.get_screenshot_as_png()
            screenshot =Image.open(BytesIO(screenshot))
    
            return screenshot
        def update_style(self):
            '''
                修改图片的style属性,显示无缺口的图片
            '''
            js = 'document.querySelectorAll("canvas")[3].style="display:block"'
            self.driver.execute_script(js)
            time.sleep(2)
    
        def get_position(self):
            '''
                获取截取验证码时的四条边
            '''
            #定位到登陆按钮
            bt_login = self.driver.find_element_by_xpath('//a[@class="btn btn-login"]')
            #模拟点击
            bt_login.click()
            time.sleep(2)
            #获取验证码图片对象
            code_img = self.driver.find_element_by_xpath('//canvas[@class="geetest_canvas_slice geetest_absolute"]')
            time.sleep(2)
    
            location = code_img.location
            size = code_img.size
    
            #screenshot = self.get_screenshot()
            #print(screenshot.size)
    
            #计算图片截取区域(左,上,右,下,的坐标值)
            left,top,right,buttom = location['x'],location['y'],location['x']+size['width'],location['y']+size['height']         return left,top,right,buttom     def get_image(self):         '''             截取验证码图片         '''         #获取验证码位置         position = self.get_position()         #从屏幕截图中抠出有缺口的验证码图片         captcha1 = self.get_screenshot().crop(position)         #修改style属性,显示无缺口的验证码图片         self.update_style()         #从屏幕截图中抠出无缺口的验证码图片         captcha2 = self.get_screenshot().crop(position)         with open('captcha1.png','wb') as f1 ,open('captcha2.png','wb') as f2:             captcha1.save(f1)             captcha2.save(f2)         return captcha1,captcha2

    7. 比较两个验证码图片获取验证码滑块的偏移量

        def is_pixel_equal(self,img1,img2,x,y):
            '''
                判断两张图片的同一像素点的RGB值是否相等
            '''
            pixel1,pixel2= img1.load()[x,y],img2.load()[x,y]
            #print(pixel1,pixel2)
            #设定一个比较基准
            sub_index = 60
    
            #比较
            if abs(pixel1[0]-pixel2[0])< sub_index and abs(pixel1[1]-pixel2[1])< sub_index and abs(pixel1[2]-pixel2[2])< sub_index:
                return True
            else:
                return False
    
        def get_gap_offset(self,img1,img2):
            '''
                获取缺口的偏移量
            '''
            x = int(img1.size[0]/4.2)
            for i in range(x,img1.size[0]):
                for j in range(img1.size[1]):
                    #两张图片对比,(i,j)像素点的RGB差距,过大则该x为偏移值
                    if not self.is_pixel_equal(img1,img2,i,j):
                        x = i
                        return x
            return x


    8.使用偏移值计算移动操作(轨迹)

        def get_track(self,offset):
            '''
               模拟人为拖动验证码滑块 
            '''
            track = []
            #滑块起始x坐标
            current = 5
            #变速临界值
    
            border_point = int(offset*3/5)
            #设置时间间隔
            t = 0.2
            #设置初速度
            offset +=4
            v = 0
            #循环直到滑动到偏移值时退出
            while current < offset:
                #根据是否临界点改变运动状态
                if current < border_point:
                    #加速度
                    a = 1
                else:
                    a =-0.5
                v0 = v
                v = v0 + a*t
    
                move = v0*t +0.5*a*t*t
    
                current += move
    
                track.append(round(move))
    
            return track

    9.操作滑块按钮,模拟拖动滑块做验证登录

        def shake_mouse(self):
            """
            模拟人手释放鼠标抖动
            :return: None
            """
            ActionChains(self.driver).move_by_offset(xoffset=-2,yoffset=0).perform()
            ActionChains(self.driver).move_by_offset(xoffset=2,yoffset=0).perform()
    
        def operate_slider(self,track):
            '''
               拖动滑块
            '''
            #获取拖动按钮
            back_tracks = [-1,-1,-2,-1]
            slider_bt = self.driver.find_element_by_xpath('//div[@class="geetest_slider_button"]')
    
            #点击拖动验证码的按钮不放
            ActionChains(self.driver).click_and_hold(slider_bt).perform()
    
            #按正向轨迹移动
            for i in track:
                ActionChains(self.driver).move_by_offset(xoffset=i,yoffset=0).perform()
               #先加速后减速效果也不是很好。
               #每移动一次随机停顿0-1/100秒之间骗过了极验,通过率很高
                time.sleep(random.random()/100)
            time.sleep(random.random())
            #按逆向轨迹移动
            for i in back_tracks:
                time.sleep(random.random()/100)
                ActionChains(self.driver).move_by_offset(xoffset=i,yoffset=0).perform()
            #模拟人手抖动
            self.shake_mouse()
            time.sleep(random.random())
            #松开滑块按钮
            ActionChains(self.driver).release().perform()
    
    
        def do_captcha(self):
            '''
                实现处理验证码
            '''
            #有缺口,无缺口图片
            img1,img2 = self.get_image()
            #比较两个验证码图片获取验证码滑块的偏移量
            offset = self.get_gap_offset(img1,img2)
            print(offset)
    
            #使用偏移值计算移动操作
            track = self.get_track(offset)
    
            #操作滑块按钮,模拟拖动滑块做验证登录
            self.operate_slider(track)
    
        def login(self):
            '''
            实现主要的登陆逻辑
            '''
            #来到登陆界面并输入账号密码
            self.input_user_pwd()
            #处理验证码
            self.do_captcha()
    
    
            #关闭浏览器
            self.close()
    
        def run(self):
            self.login()
    
    if __name__ == '__main__':
        bili =Bilibili()
        bili.run()
    本博客为记录本人遇到问题时所找到的解决方案,且均经过本人亲测可用,如有侵权请联系添加来源或删除文章,谢谢。
  • 相关阅读:
    python3.6中 字典类型和字符串类型互相转换的方法
    "sorted()"中的"Key Functions"
    tuple unpacking
    理解"__repr__"
    Python中的"Special Method"
    abstractmethod
    JavaScript括号中什么什么不加引号什么时候加引号?
    加载网页时速度慢的一些知识点
    Login登录页面的制作流程(摘要)
    JavaScript总结1
  • 原文地址:https://www.cnblogs.com/heymonkey/p/11727939.html
Copyright © 2011-2022 走看看