关于滑块验证无原背景的selenium简单处理

记录一下,滑块分为几种,由于找不到有原背景可以对比出像素位置的,其他的也做不来,就找了这个先入门凑活一下,针对头条的登录作为举例:https://sso.toutiao.com/login/

无事先百度谷歌,不行就多打几个空格,总会有回应的,把原理搞明白了再下手具体操作,对于接触到一个未知领域,能够很快入行就显得很牛逼了,反正我不是。

中途学习借鉴到:https://www.cnblogs.com/lmx123/p/9246215.html , https://www.kancloud.cn/aollo/aolloopencv/269602


 关于滑块验证无原背景的selenium简单处理_第1张图片

 

 思路:

  1.   分析页面拿到背景图
  2.   计算滑块所需要的距离,即缺口位置
  3.   计算滑动轨迹
  4.        进行滑动

 

  分析:分析页面可以找到小滑块和大背景是两个图片,缺口和大背景是一张图片,所以直接算出距离是不太可能,按照selenium进行滑动,需要计算出滑动的距离,可以考虑图片识别(pillow, cv2)进行边缘检测或者降噪(反正能实现目的就可以),中间肯定会出现得到距离不准确的问题(先细心搞懂原理做出来,后面自己看着处理就好,别太在意冗余什么的),对于不准确的范围要自己进行判断。得到距离便可以进行滑动,但是滑动的太人机了肯定不行(一般都会识别),可以按照高中位移内容X=1/2*a*t*t (a为加速度,t为时间)可以得到一串位移的和为距离的列表,然后进行滑动就像人了(当然也可以划过头然后划回来)。

  


 

  具体代码实现:

  •  分析页面拿到背景图

      通过分析背景分析距离,所以肯定是越精确越好,图片识别也好识别,如果就拿screenshot,就准备按尺寸进行截取,具体参数,网站各不一样,但是都是常数

def save_img(self):  # 懒得写显式等待了
        # 进行初始点击到滑块
        self.driver.find_element_by_xpath('//*[@id="login-type-account"]/span').click()
        time.sleep(0.3)
        self.driver.find_element_by_id("user-name").send_keys(self.username)
        time.sleep(0.3)
        self.driver.find_element_by_id("password").send_keys(self.password)
        time.sleep(0.3)
        self.driver.find_element_by_class_name("bytedance-submit").click()
        time.sleep(2)
        # 获取全背景图,进行裁剪保存
        img = self.driver.find_element_by_class_name("sc-iwsKbI")
        time.sleep(0.3)
        location = img.location
        print("location: ", location)
        size = img.size
        print("验证码大小:", size)
        print(img.__dir__())
        left, up, right, down = location["x"], location["y"], location["x"] + size["width"], location["y"] + size[
            "height"]
        print("截取后的图片信息:", left, up, right, down)
        # 保存大背景图
        self.driver.save_screenshot("toutiao.png")
        # 截取小验证图
        need_bg_img = Image.open("toutiao.png")
        img_writer = need_bg_img.crop((left, up, right, down))  # 指定上下左右截取
        img_writer.save("captcha.png")
  • 计算滑块所需要的的距离

                 关于滑块验证无原背景的selenium简单处理_第2张图片     关于滑块验证无原背景的selenium简单处理_第3张图片

              原图                        灰度图

                                           

    左边的滑块y轴距离是不确定的,但是x轴是确定的,所以可以直接拿到x距离。然后右边是不固定的,可以通过对图像进行降噪或者边缘处理,由于技术问题,我直接进行变为灰度值,发现也还可以弄,获取到所有灰度值为255的,根据出现的y坐标频率最高的以及数值最大的判断得出缺口的x坐标,即缺口距离y轴距离。

def get_distance(self):
        # 转成灰度图进行处理
        img = cv2.imread("captcha.png", 0)  # 由于Canny只能处理灰度图,所以将读取的图像转成灰度图
        img = cv2.GaussianBlur(img, (3, 3), 0)  # 用高斯平滑处理原图像降噪。若效果不好可调节高斯核大小
        canny = cv2.Canny(img, 200, 600)  # 调用Canny函数,指定最大和最小阈值,其中apertureSize默认为3。
        # cv2.imshow('Canny', canny)
        # 获取图片大小
        x_len, y_len = canny.shape
        # 遍历每个像素获取到 X 值,进行统计
        x_arr = []
        for i in range(1, x_len):
            for j in range(1, y_len):
                if canny[i, j] == 255.:
                    print(i, j)
                    x_arr.append(j)
        print("顺序打印看一下:",sorted(x_arr))
        # 根据频率统计得到缺口距离y轴距离
        former_dict = Counter(x_arr).most_common(5)
        far_distance = max(dict(former_dict).keys())
        distance = far_distance - self.margin_left
        return distance

 

 

  • 计算滑动轨迹

   只要看起来不像人机,怎么写都行,这里使用返回一个轨迹列表。

 def get_track(self, distance):  # 人为滑动是先慢 中快 后慢
        """
        根据偏移量获取移动轨迹
        :param distance: 偏移量
        :return: 移动轨迹列表
        """
        track = []
        current = 0 # 当前位移
        mid = distance * 4 / 5 #  设定一个阈值进行改变加速度
        t = 1   # 计算间隔
        v = 0   # 初速度
        while current < distance:
            if current < mid:
                a = 1  # 加速度为正1
            else:
                a = -2 # 加速度为负2
            v0 = v  # 初速度v0
            v = v0 + a * t   # 当前速度v = v0 + at
            # 移动距离x = v0t + 1/2 * a * t^2
            move = v0 * t + 1 / 2 * a * t * t
            current += move # 当前位移
            track.append(round(move))   # 加入轨迹
        return track
  • 进行滑动
    tt = TouTiao()
    tt.save_img()
    distance = tt.get_distance()
    button = tt.driver.find_element_by_class_name("secsdk-captcha-drag-icon")
    ActionChains(tt.driver).click_and_hold(button).perform()
    print("获取到的distance为:",distance)
    dis_list = tt.get_track(distance)
    # 查看get_track函数的长短是否匹配
    dis_list = list(filter(lambda x: x > 0, dis_list))
    print("过滤掉为0的轨迹列表:",dis_list)
    print("reduce获取到和值:",reduce(lambda x, y: x + y, dis_list))
    for dis in dis_list:
        ActionChains(tt.driver).move_by_offset(xoffset=dis, yoffset=0).perform()
    ActionChains(tt.driver).release(button).perform()
    time.sleep(0.3)

 

内容就这些,但是还是碰到了一些坑:

  1.  有些滑块是通过css来控制背景图,需要仔细观察一下,因为还是对比图成功率高一些
  2.  尽量不要使用chains= ActionChains(driver),进行使用chains调用方法时,它会在原有的事件上再执行一遍事件(有点搞)
  3.  生成轨迹列表的时候值尽量不要相差太大,相差太大无法通过

小结:

  第一次写博客,sbxx(随便写写)吧,本来是想做有原背景的,因为有的话,只需要背景图和有缺口图对比,然后遍历像素就可以得到缺口的位置。然后没找着,就找个简单一点的把原理整明白。果然看点东西容易,写点东西还真要点东西,做个记录,慢慢来吧。

附上源码地址:隅偶的gitee

你可能感兴趣的:(滑块验证)