|
python spI命令 spy++ python
SPY++的使用和Python操作
1、spy++的基本操作
1.1 窗口属性查找
1.2 窗口spy++定位
2、python与spy++
Source Code
Use
下载 Spy++:VC6.0下面的spy++,小巧方便
1、spy++的基本操作
python spI命令 spy++ python
1.1 窗口属性查找
python spI命令 spy++ python
拖住中间的“寻找工具”放到想要定位的软件上,然后松开
python spI命令 spy++ python
以微信为例,我们会得到“微信”这个窗口的句柄,为“00031510”,注意这个句柄是“十六进制”,即“0x31510”。
点击ok我们会看到更详细的属性信息
1.2 窗口spy++定位
python spI命令 spy++ python
同理拖放到“微信”上,获取到“微信”的界面
点击ok,会直接定位到“微信”
在这里我们会看到一条信息
00031510 “微信” WeChatMainWndForPC
– 00031510:代表十六进制的窗口句柄
– 微信:代表窗口标题
– WeChatMainWndForPC:代表窗口的类名
2、python与spy++
Source Code
- #!/usr/bin/python
- # -*- coding: utf-8 -*-
- # @Time : 2021/1/27 10:50
- # @Author : SandQuant
- import collections
- from win32 import win32gui
- import pyautogui
- import sys
- class PySpy(object):
- Window = collections.namedtuple('Window', ['caption', 'class_name', 'hwnd_py', 'hwnd_spy'])
- def __init__(self):
- pass
- @classmethod
- def window_attr(cls, hwnd_py):
- """
- 显示窗口的属性
- :param hwnd_py: 窗口句柄(十进制)
- :return: Window
- """
- return cls.Window(
- caption=win32gui.GetWindowText(hwnd_py),
- class_name=win32gui.GetClassName(hwnd_py),
- hwnd_py=hwnd_py,
- hwnd_spy=hex(hwnd_py),
- )
- @classmethod
- def show_top_windows(cls):
- """
- 列出所有的顶级窗口及属性
- :return: 全部的顶层窗口及对应属性
- """
- containers = []
- win32gui.EnumWindows(lambda hwnd, param: param.append(cls.window_attr(hwnd)), containers)
- return containers
- @classmethod
- def find_top_window(cls, caption) -> list:
- """
- 查找窗体
- :param caption: 窗口标题部分文字
- :return:
- """
- return [w for w in cls.show_top_windows() if caption in w.caption]
- @classmethod
- def find_sub_windows(cls, hwnd_py=None, class_name=None, caption=None, index=None):
- """
- 返回窗体下全部的子窗体,默认主窗体下的窗体
- :param hwnd_py: 句柄 十进制
- :param class_name: 窗口类名,返回特定类名
- :param caption: 窗口标题,返回特定标题
- :param index: 位置,返回特定位置的窗口
- :return: 包含属性的全部子窗口
- """
- num = 0
- handle = 0
- sub_windows = []
- while True:
- # find next handle, return HwndPy
- handle = win32gui.FindWindowEx(hwnd_py, handle, class_name, caption)
- if handle == 0:
- # no more handle
- break
- # get handle attribution
- attr = cls.window_attr(handle)
- # append to list
- sub_windows.append(tuple(list(attr) + [num]))
- num += 1
- if index is not None:
- return sub_windows[index]
- else:
- return sub_windows
- @classmethod
- def show_all_windows(cls, window=None, handle_list=None, handle_dict=None):
- """
- 生成窗口全部对应的关系
- :param window: 目标父窗口
- :param handle_list: 默认为[[None]]
- :param handle_dict: 用于存放对应关系
- :return: 返回目标窗口下全部子父窗口的字典
- """
- if not handle_list and not handle_dict:
- handle_list = [[None]]
- handle_dict = dict()
- sys.setrecursionlimit(1000000)
- if window:
- handle_list[-1][0] = window
- handles = cls.find_sub_windows(handle_list[-1][0][2])
- else:
- handles = cls.find_sub_windows()
- for handle in handles:
- handle_dict[handle] = window
- # 这个根节点已经遍历完,删除
- del handle_list[-1][0]
- # 如果有叶节点,非空,则加入新的叶节点
- if handles:
- handle_list.append(handles)
- # 删除已被清空的根
- handle_list = [HandleGroup for HandleGroup in handle_list if HandleGroup]
- # 如果还有根就继续遍历,否则输出树
- if handle_list:
- return cls.show_all_windows(window=handle_list[-1][0], handle_list=handle_list, handle_dict=handle_dict)
- else:
- return handle_dict
- @classmethod
- def find_handle_path(cls, hwnd_spy, num):
- """
- 寻找特定窗口的寻找路径
- 找到全部层级的对应关系,然后反向搜索
- :param hwnd_spy: 窗口句柄(十六进制)
- :param num: 窗口所属index,在spy++内查看
- :return:
- parent_window:顶层窗口
- target_path:路径的index
- """
- all_path = cls.show_all_windows()
- key = tuple(list(cls.window_attr(int(hwnd_spy))) + [num])
- handle_path = [key]
- while True:
- key = all_path[key]
- if not key:
- handle_path = handle_path[::-1]
- parent_window = handle_path[0]
- target_path = [(i[-1]) for i in handle_path[1:]]
- return parent_window, target_path
- handle_path.append(key)
- @classmethod
- def find_target_handle(cls, window, path):
- """
- 递归寻找子窗口的句柄
- :param window: 祖父窗口的完整句柄 (WindowName, ClassName, HwndPy, HwndSpy)
- :param path: 子窗口列表
- :return: 目标窗口的完整属性
- """
- for i in range(len(path)):
- window = cls.find_sub_windows(window[2], index=path[i])
- return window
复制代码 Use
1、获取窗体属性
- # 获取句柄1902690的属性
- window = PySpy.window_attr(hwnd_py=1902690)
- print(window)
复制代码- Window(caption='百度云', class_name='ATL:011386F8', hwnd_py=1902690, hwnd_spy='0x1d0862')
复制代码 2、获取全部顶层窗体
- # 获取全部顶层窗体
- windows = PySpy.show_top_windows()[:5]
- for w in windows:
- print(w)
复制代码- Window(caption='', class_name='ForegroundStaging', hwnd_py=66032, hwnd_spy='0x101f0')
- Window(caption='', class_name='ForegroundStaging', hwnd_py=65982, hwnd_spy='0x101be')
- Window(caption='', class_name='tooltips_class32', hwnd_py=65836, hwnd_spy='0x1012c')
- Window(caption='', class_name='tooltips_class32', hwnd_py=65844, hwnd_spy='0x10134')
- Window(caption='', class_name='tooltips_class32', hwnd_py=65856, hwnd_spy='0x10140')
复制代码 3、查找指定的顶层窗体
- # 查找顶层窗体
- result = PySpy.find_top_window(caption='spy++')
- print(result)
复制代码- [Window(caption='spy++', class_name='CabinetWClass', hwnd_py=9571640, hwnd_spy='0x920d38')]
复制代码 4、查找特定父窗体下全部子窗体
- # 查找特定句柄下全部子窗体
- window = PySpy.find_sub_windows(hwnd_py=9571640)
- for w in windows:
- print(w)
复制代码- Window(caption='', class_name='ForegroundStaging', hwnd_py=66032, hwnd_spy='0x101f0')
- Window(caption='', class_name='ForegroundStaging', hwnd_py=65982, hwnd_spy='0x101be')
- Window(caption='', class_name='tooltips_class32', hwnd_py=65836, hwnd_spy='0x1012c')
- Window(caption='', class_name='tooltips_class32', hwnd_py=65844, hwnd_spy='0x10134')
- Window(caption='', class_name='tooltips_class32', hwnd_py=65856, hwnd_spy='0x10140')
复制代码 5、获取全部窗体父子对应关系
- # 生成窗口全部对应的关系
- windows = PySpy.show_all_windows(window=('spy++', 'CabinetWClass', 9571640, '0x920d38'))
- for w in windows.items():
- print(w)
复制代码- (('UIRibbonDockLeft', 'UIRibbonCommandBarDock', 1838390, '0x1c0d36', 0), ('spy++', 'CabinetWClass', 9571640, '0x920d38'))
- (('UIRibbonDockRight', 'UIRibbonCommandBarDock', 1773536, '0x1b0fe0', 1), ('spy++', 'CabinetWClass', 9571640, '0x920d38'))
- (('UIRibbonDockTop', 'UIRibbonCommandBarDock', 2756588, '0x2a0fec', 2), ('spy++', 'CabinetWClass', 9571640, '0x920d38'))
- ...
- (('', 'ScrollBar', 52956100, '0x3280bc4', 0), ('', 'CtrlNotifySink', 3607746, '0x370cc2', 1))
- (('', 'ReBarWindow32', 11603876, '0xb10fa4', 0), ('', 'WorkerW', 2755884, '0x2a0d2c', 1))
- (('', 'ToolbarWindow32', 2427436, '0x250a2c', 0), ('', 'ReBarWindow32', 11603876, '0xb10fa4', 0))
复制代码 6、获取特定窗体的查找路径
- # 寻找特定窗口的寻找路径
- parent, pth = PySpy.find_handle_path(hwnd_spy=0xb10fa4, num=0)
- print(parent, pth)
复制代码- ('spy++', 'CabinetWClass', 9571640, '0x920d38', 232) [5, 1, 0]
复制代码 7、根据查找路径获取到句柄信息(6的逆过程)
- # 根据顶层窗体和路径 寻找子窗口的句柄
- window = PySpy.find_target_handle(window=parent, path=pth)
- print(window)
复制代码- ('', 'ReBarWindow32', 11603876, '0xb10fa4', 0)
复制代码 8、根据窗体句柄,找到窗体位置
- # 根据句柄定位窗体
- x, y, m, n = win32gui.GetWindowRect(9571640)
- pyautogui.moveTo((x + m) / 2, (y + n) / 2)
复制代码
|
|