新版滑动验证码

今天的主角是滑动验证码,现在有很多网站使用了极验验证码来智能反爬虫,其中有一种是滑动验证码,具体来说就是拖动滑块来拼合图像,若图像完全拼合,则验证成功。下图是B站的登录验证码,便是采用了极验的滑动验证码,一起来看看如何破解吧!

先打开B站的登录页面,https://passport.bilibili.com/login,输入账号密码之后点击登录便会弹出上述的滑动验证码。

将任务拆分有助于我们解决问题,解决这个滑动验证码我们可以分为这么两个步骤:

1)识别图片缺口

2)模拟拖动滑块

那么就一步一步来吧~

图片缺口识别

可以看到的是缺口图的颜色与周围有显著不同,我们只需要拿到不含缺口的原图进行对比就能够找到这个缺口的坐标。

打开开发者工具,看源代码上是否包含两张图片的url链接,这样我们可以直接下载下来分析对比。不巧的是,我们没有发现它的踪迹。

但当我们将上图源代码中的类别为"geetest_canvas_fullbg geetest_fade geetest_absolute"的style设置为空,即可显示没有缺口的原图。

知道如何获得这两张图片之后,我们可以通过get_geetest_image函数来获取滑动验证码的图片,具体是用了 Selenium 工具选取图片元素,然后得到其所在位置以及大小,随后获取整个网页的截图,再将这个滑动验证码从截图中裁切出来。

    def get_geetest_image(self,name,flag):
        
        """
        获得验证码图片        
        """
        bottom,top,left,right=self.get_position(flag)
        print("验证图片位置",bottom,top,left,right)
        screenshot=self.get_screenshot()
        captcha=screenshot.crop((left,bottom,right,top))
        captcha.save(name)
        return captcha

    def get_position(self, flag):
        
        """
        获取验证码图片位置
        """
        img=self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "canvas.geetest_canvas_slice")))
        time.sleep(2)                
        if flag:
            # 执行js获取不带缺口的原图
            self.browser.execute_script('document.getElementsByClassName("geetest_canvas_fullbg")[0].setAttribute("style", "")')
        else:
            # 执行js,把缺口复原
            self.browser.execute_script('document.getElementsByClassName("geetest_canvas_fullbg")[0].setAttribute("style", "opacity: 1; display: none;")')
        location=img.location
        print("图片坐标为:{}".format(location))
        size=img.size
        print("图片大小为:{}".format(size))
        bottom,top,left,right=location["y"],location["y"]+size["height"],location["x"],location["x"]+size["width"]
                           
        return (bottom,top,left,right)

我们通过selenium执行js代码,获取不带缺口的原图和我们最先见到的有缺口的图。

图片获取之后,来对比图片各个像素通道的差异来获取缺口的位置就行。我们宽泛的认为,像素相差在一定范围内视为相同,像素相差大于阈值视为发现缺口,便由此得到了缺口的坐标信息。

      def get_gap(self, image1, image2):
        
        """
        获取缺口位置,通过比较像素值
        """
        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):
                    return i
        return LEFT

    def is_pixel_equal(self,image1,image2,x,y):
        
        """
        像素值比较,若三个通道均为出现超过阈值的变化,返回True
        """
        pixel1=image1.load()[x, y]
        pixel2=image2.load()[x, y]
        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
  

加上LEFT这个偏移量,是因为带缺口的图还附带了滑块,我们需要将滑块的长度范围舍弃,即在滑块的右侧开始像素的比较,这样我们就可以得到缺口的位置了。

模拟拖动滑块

要拖动滑块我们需要先得到滑块通过简单的selenium操作即可。

    def get_slider(self):
        
        """
        获取滑块
        """
        return self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, "geetest_slider_button")))

这里需要用到简单的高中物理知识,为了让selenium模拟人的操作,我们需要将滑块先加速运动,再减速运动,这样会比较符合人的操作。我们采用匀加速和匀减速的方法,方便套用物理公式。模拟前4/5路程为匀加速路程,后1/5路程是匀减速路程,t是计算的时间间隔。

    def get_track(self,distance):
        
        """
        获取滑块移动轨迹的列表,distance是缺口的左侧横坐标值
        """
        track=[]
        current=0
        mid=distance*0.8
        t=0.2
        v=0
        while current<distance:
            if current<mid:
                a=2.5
            else:
                a=-3.5
            v0=v
            v=v0+a*t
            move=v0*t+ 0.5*a*t*t
            current+=move
            track.append(round(move))
        return track

然后,我们只需要按照计算得到的运动轨迹操控小滑块运动即可。下面是破解过程展示。

本文分享自微信公众号 - 算法与数据之美(algo_and_data),作者:斐波那契小李

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-08-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 花式照片墙

    观众老爷们,小李今天给大家展示一下我“精湛”的厨艺。如题所示,花式照片墙这道小菜马上给大家端上来,大家吃好喝好。

    老肥码码码
  • 用Python做一个久坐提醒小助手

    整体的构思类似于一个番茄时钟,提供一个倒计时功能并且在完成计时时发出警告。主要分为如下几个模块,一是时间选择模块,二是按钮模块,控制计时开始、暂停以及恢复,三是...

    老肥码码码
  • 一键下载掌盟文章

    爬了不少网页,还没试过app,今天就来实战一下吧!本次目标是爬取掌上英雄联盟app的文章,需要备有Fiddler,MongoDB(可选),一个安装了掌上英雄联盟...

    老肥码码码
  • 北京四环堵车引发的智能交通大构想

    ‍‍‍‍‍这是作者关于智能交通协议(Intelligent Transport Protocol)的构想,欢迎留言讨论。

    AI科技大本营
  • 12306破解!

    验证码(CAPTCHA),是一种区分用户是计算机还是人的公共全自动程序。对于研究爬虫来说,这应该是爬虫的“天敌”。

    谭庆波
  • [-Flutter插件篇 -] 从自定义插件开始说起

    张风捷特烈
  • python3+opencv+tkint

    其中所使用到的训练参数数据下载地址:https://github.com/opencv/opencv/tree/master/data/haarcascades

    py3study
  • 算法--分治算法

    版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。

    奋飛
  • 58同城数据库架构设计思路(下)

    《58同城数据库架构设计思路》(下) WOT(World Of Tech)2015,互联网运维与开发者大会将在北京举行,会上58同城分享了《大数据量下,58同城...

    架构师之路
  • 物联网通信架构总结

     本文从宏观上介绍IoT的通信架构,让大家都日渐频繁的物联网设备工作原理有一个初步的理解,主要分为了直连、网关、云三种模式。 1. 直连模式(direct in...

    ascii0x03

扫码关注云+社区

领取腾讯云代金券