• 基于win32实现TB登陆滑动验证


    先谈理论,淘宝 taobao.com 的所有登陆系统,都是基于sso来实现的,基本大同小异

    在这里插入图片描述

    滑动验证触发条件:

    1. 此账户多次异常失败
    2. 该账户在多种ip环境下登陆
    3. 被系统检测到自动化

    失败条件:

    1. 失败一次后,继续使用当前cookies
    2. 滑动速度太慢
    3. 网络太忙 ( 滑动成功,但是存在无效cookie)

    解决方法:

    每次登陆前,必须保证,当前异常cookie,每次登陆前清除一次即可

    清除cooKie

    由于playwright清理当前cookies不干净,所以采用浏览器强制清除cookies
    在这里插入图片描述

    def clear_cookie(handle: int, point, point2, point3, point4):
    	
        win32gui.SetForegroundWindow(handle)
        win32gui.ShowWindow(handle, 3)  # 窗口最大化
        # left, top, right, bottom = win32gui.GetWindowRect(handle)
        # width = right - left
        # height = bottom - top
        # # # 计算指定检查点的坐标
        # x = left + int(point[0] * width)
        # y = top + int(point[1] * height)
        x = point[0]
        y = point[1]
        win32api.SetCursorPos(point)
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, x, y, 0, 0)  # 鼠标左键按下
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, x, y, 0, 0)  # 鼠标左键抬起
        x = point2[0]
        y = point2[1]
        win32api.SetCursorPos(point2)
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, x, y, 0, 0)  # 鼠标左键按下
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, x, y, 0, 0)  # 鼠标左键抬起
        x = point3[0]
        y = point3[1]
        win32api.SetCursorPos(point3)
        time.sleep(0.1)
        for i in range(15):
            win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, x, y, 0, 0)  # 鼠标左键按下
            win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, x, y, 0, 0)  # 鼠标左键抬起
        x = point4[0]
        y = point4[1]
        win32api.SetCursorPos(point4)
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, x, y, 0, 0)  # 鼠标左键按下
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, x, y, 0, 0)  # 鼠标左键抬起
        time.sleep(0.1)
        win32api.keybd_event(0x0D, 0, 0, 0)
        win32api.keybd_event(0x0D, 0, win32con.KEYEVENTF_KEYUP, 0)
    
    def findTitle(window_title):
        '''
        查找指定标题窗口句柄
        @param window_title: 标题名
        @return: 窗口句柄
        '''
        hWndList = []
        # 函数功能:该函数枚举所有屏幕上的顶层窗口,办法是先将句柄传给每一个窗口,然后再传送给应用程序定义的回调函数。
        win32gui.EnumWindows(lambda hWnd, param: param.append(hWnd), hWndList)
        for hwnd in hWndList:
            # 函数功能:该函数获得指定窗口所属的类的类名。
            # clsname = win32gui.GetClassName(hwnd)
            # 函数功能:该函数将指定窗口的标题条文本(如果存在)拷贝到一个缓存区内
            title = win32gui.GetWindowText(hwnd)
            if (window_title in title):
                return title, hwnd
        return ()
    
    
    
    def del_cookies(self, window_title):
          logger.info("清空cookies中")
          try:
              self.context.clear_cookies()
              hwnd = findTitle(window_title)
              if global_config.active == "prod":
                  clear_cookie(hwnd[1], (144, 53), (192, 173), (624, 558), (900, 549))  # 生产
              else:
                  clear_cookie(hwnd[1], (3032, 51), (3128, 174), (3736, 548), (4006, 554))
          except Exception as e:
              logger.error(f"清除cookie异常, {str(e)}")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    滑动验证

    方式一:win32 api获取窗口句柄,选择固定位置 成功率高

    需要提前录制当前桌面的鼠标轨迹

    def move(handle: int, point: tuple[int], move_point: tuple[int]):
        """
            后台移动鼠标
        """
        try:
            # 激活窗口刀前台
            win32gui.SetForegroundWindow(handle)
            win32gui.ShowWindow(handle, 3)  # 窗口最大化
            left, top, right, bottom = win32gui.GetWindowRect(handle)
            width = right - left
            height = bottom - top
            # # 计算指定检查点的坐标
            x = left + int(point[0] * width)
            y = top + int(point[1] * height)
    
            x1 = left + int(point[0] * width) + random.randint(1, 20)
            y1 = top + int(point[1] * height)
            # x = point[0]
            # y = point[1]
            # 移动鼠标指针
            win32api.SetCursorPos(point)
            win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, x, y, 0, 0)  # 鼠标左键按下
            # time.sleep(0.5)
            # win32api.SetCursorPos(move_point)
            for i in range(x, x1):
                win32api.mouse_event(win32con.MOUSE_MOVED, i, y1, 0, 0)  # 鼠标左键按下
            win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, x1, y1, 0, 0)  # 鼠标左键抬起
        except Exception as e:
            pass
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    方式二: 原自动化滑动,成功率中

    def un_login_lock(self, distance: int, locator: Locator) -> None:
        locator.blur()
        box = locator.bounding_box()
        tracks = get_track(distance)
        x = int(box["x"] + box["width"] / 2)
        y = int(box["y"] + box["height"] / 2)
        locator.hover()
        self.page.mouse.down()
        self.page.mouse.move(x, y + random.randint(10, 20), steps=12)
        for track in tracks:
            self.page.mouse.move(track + x, y + random.randint(10, 20), steps=9)
            x = x + track
        self.page.mouse.up()
        self.page.wait_for_timeout(random.randint(2200, 3200))
    附录:绕过Webdriver检测可增加浏览器反识别概率,可选不加
    def webdriver(self):
        # 绕过Webdriver检测
        js = """Object.defineProperties(navigator, {webdriver:{get:()=>undefined}});"""
        self.page.add_init_script(js)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    案例

    if locator := self.is_lock(punish[0]):
        logger.info(f"正在进行滑动验证,{locator.bounding_box()}")
        hwnd = findTitle(window_title)
        conf = {
            "start":[[4077, 583],[4079, 582],[4078,595]], # 鼠标开始的轨迹数组
            "end":[[4823, 623],[4923, 699],[4518,578]] # 鼠标结束的轨迹数组
           }
        points = eval(conf.get("config_value"))
        starts = points.get("start")
        ends = points.get("end")
        # 随机选择一个
        move(hwnd[1], starts[random.randint(0, len(starts) - 1)], ends[random.randint(0, len(ends) - 1)])
        # self.un_login_lock(500, locator)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    虽然小概率出现异常,加入重试机制后,基本没出现过问题

  • 相关阅读:
    重定向和转发
    【PWN】03.汇编分析
    常见数据类型的占用字节数以及类型转换需要注意的事项
    使用HTTP代理上网安全吗?
    反射型XSS实验(1)
    Excel——对其他工作表和工作簿的引用
    postgres in (?,?) 和 =any(?) 用法/性能对比
    开源云财务软件,财务软件源码,永久免费财务软件
    【APP移动端自动化测试】第二节.Appium介绍和常用命令代码实现
    02 python基本数据结构
  • 原文地址:https://blog.csdn.net/weixin_45904404/article/details/133138828