python中spy++的使用超详细教程


Posted in Python onJanuary 29, 2021

1、spy++的基本操作

python中spy++的使用超详细教程 

1.1 窗口属性查找

python中spy++的使用超详细教程

拖住中间的“寻找工具”放到想要定位的软件上,然后松开

python中spy++的使用超详细教程

以微信为例,我们会得到“微信”这个窗口的句柄,为“00031510”,注意这个句柄是“十六进制”,即“0x31510”。

python中spy++的使用超详细教程

点击ok我们会看到更详细的属性信息

python中spy++的使用超详细教程 

1.2 窗口spy++定位

python中spy++的使用超详细教程

同理拖放到“微信”上,获取到“微信”的界面

python中spy++的使用超详细教程

点击ok,会直接定位到“微信”

python中spy++的使用超详细教程

在这里我们会看到一条信息00031510 “微信” WeChatMainWndForPC
? 00031510:代表十六进制的窗口句柄
? 微信:代表窗口标题
? WeChatMainWndForPC:代表窗口的类名


2、python结合spy++

导入必要的库

import win32con
from win32 import win32gui
from win32 import win32clipboard as w
import pyautogui
import sys

2.1 获取窗口全部属性

def show_window_attr(hwnd):
 """
 显示窗口的属性
 :param hwnd: 窗口句柄(十进制)
 :return: 所有的属性
 WindowName: 窗口标题
 ClassName: 窗口类名
 HwndPy: 窗口句柄(十进制)
 HwndSpy: 窗口句柄(十六进制)
 """
 if not hwnd:
 return
 WindowName = win32gui.GetWindowText(hwnd)
 ClassName = win32gui.GetClassName(hwnd)
 HwndPy = hwnd
 HwndSpy = hex(hwnd)
 return (WindowName, ClassName, HwndPy, HwndSpy)

已经知道“微信”十六进制的窗口句柄,先转化为十进制,可获取全部属性

>>> int(0x31510)
202000
>>> show_window_attr(202000)
('微信', 'WeChatMainWndForPC', 202000, '0x31510')

2.2 获取全部顶层窗口

def show_top_windows():
 """
 列出所有的顶级窗口及属性
 :return: 全部的顶层窗口及对应属性
 """
 hwndList = []
 win32gui.EnumWindows(lambda hwnd, param: param.append(show_window_attr(hwnd)), hwndList)
 return hwndList

获取到的是整个桌面所有的窗口

python中spy++的使用超详细教程

>>> show_top_windows()
[('CClipboardThread', 'CClipboardThread', 2165890, '0x210c82'), ('G', 'GDI+ Hook Window Class', 463410, '0x71232'), ('', 'ForegroundStaging', 66338, '0x10322'), ('', 'ForegroundStaging', 66294, '0x102f6'), ('', 'tooltips_class32', 66234, '0x102ba'), ('', 'tooltips_class32', 66204, '0x1029c'), ('', 'tooltips_class32', 66200, '0x10298'), ('', 'tooltips_class32', 66196, '0x10294'), ('', 'tooltips_class32', 66192, '0x10290'), ('', 'tooltips_class32', 66174, '0x1027e'), ('', 'tooltips_class32', 66166, '0x10276'), ('', 'tooltips_class32', 66154, '0x1026a'), ('', 'tooltips_class32', 66888, '0x10548'), ('', 'tooltips_class32', 131762, '0x202b2'), ('', 'Q360NetmonClass', 197502, '0x3037e'), ('', 'tooltips_class32', 66208, '0x102a0'), ('', 'tooltips_class32', 11404742, '0xae05c6'), ('', 'tooltips_class32', 66214, '0x102a6'), ('', 'tooltips_class32', 66228, '0x102b4'), ('', 'tooltips_class32', 66222, '0x102ae'),

2.3 模糊查找主窗体

def FindFuzzyTopWindow(FuzzyWindowName=None):
 """
 根据标题模糊查找全部符合条件的主窗体
 :param FuzzyWindowName: 窗口标题部分文字
 :return:
 """
 all_windows = show_top_windows()
 result = []
 for window in all_windows:
 if FuzzyWindowName in window[0]:
 result.append(window)
 return result
  • 有时候我们需要通过“部分名称”来找出主窗体的属性
  • 找出了窗体标题含有“同花顺”的全部窗体
>>> FindFuzzyTopWindow(FuzzyWindowName='同花顺')
[('同花顺(v8.80.80) - 我的板块', 'Afx:400000:b:10003:6:d60ca7',
 134184, '0x20c28'), ('同花顺股灵通', '#32770', 462652, '0x70f3c')]

2.4 获取目标父窗体下的全部子窗体

def FindSubHandles(pHandle=None, ClassName=None, WinName=None, index=None):
 """
 返回窗体下全部的子窗体,默认主窗体下的窗体
 :param pHandle: 窗口句柄(十进制)
 :param ClassName: 窗口类名,返回特定类名
 :param WinName: 窗口标题,返回特定标题
 :param index: 位置,返回特定位置的窗口
 :return: 包含属性的全部子窗口
 """
 num = 0
 handle = 0
 SubHandlesList = []
 while True:
 # find next handle, return HwndPy
 handle = win32gui.FindWindowEx(pHandle, handle, ClassName, WinName) 
 if handle == 0:
 # no more handle
 break
 # get handle attribution
 attr = show_window_attr(handle)
 # append to list
 SubHandlesList.append(tuple(list(attr) + [num]))
 num += 1
 if index is not None:
 return SubHandlesList[index]
 else:
 return SubHandlesList
  • 以刚刚“同花顺”为例,十进制句柄为134184
  • 其他参数在特定场合下会起作用
>>> FindSubHandles(pHandle=134184)
[('', 'Button', 69090, '0x10de2', 0), 
('', 'ToolbarWindow32', 69272, '0x10e98', 1),
 ('', 'msctls_statusbar32', 265490, '0x40d12', 2), 
 ('', 'msctls_statusbar32', 134664, '0x20e08', 3), 
 ('', 'AfxFrameOrView42s', 134212, '0x20c44', 4), 
 ('', 'AfxControlBar42s', 134180, '0x20c24', 5), 
 ('', 'AfxControlBar42s', 134192, '0x20c30', 6), 
 ('功能树', 'AfxControlBar42s', 134194, '0x20c32', 7),
 ('', 'AfxControlBar42s', 134196, '0x20c34', 8), 
 ('HqEmbededTradeContainer', 'Afx:400000:0', 69270, '0x10e96', 9), 
 ('功能树', 'Afx:400000:8:10003:10006e:0', 69320, '0x10ec8', 10), 
 ('', 'Afx:400000:0', 69430, '0x10f36', 11), 
 ('', 'Afx:400000:0', 69432, '0x10f38', 12)]

对比SPY++中的结果完全一致

python中spy++的使用超详细教程 

2.5 获取某个父窗口

下面全部的子窗口,遍历所有窗口 这里获取到的是全部层级的子窗口

def ShowAllHandle(pHandle=None, HandleList=[[None]], HandleDict=dict()):
 """
 生成窗口全部对应的关系
 :param pHandle: 目标父窗口
 :param HandleList: 默认为[[None]]
 :param HandleDict: 用于存放对应关系
 :return: 返回目标窗口下全部子父窗口的字典
 """
 sys.setrecursionlimit(1000000)
 if pHandle:
 HandleList[-1][0] = pHandle
 handles = FindSubHandles(HandleList[-1][0][2])
 else:
 handles = FindSubHandles()
 for handle in handles:
 HandleDict[handle] = pHandle
 # 这个根节点已经遍历完,删除
 del HandleList[-1][0]
 # 如果有叶节点,非空,则加入新的叶节点
 if handles:
 HandleList.append(handles)
 # 删除已被清空的根
 HandleList = [HandleGroup for HandleGroup in HandleList if HandleGroup]
 # 如果还有根就继续遍历,否则输出树
 if HandleList:
 return ShowAllHandle(pHandle=HandleList[-1][0], HandleList=HandleList, HandleDict=HandleDict)
 else:
 return HandleDict

pHandle:这个参数设置为

('同花顺(v8.80.80) - 我的板块', 'Afx:400000:b:10003:6:d60ca7', 134184, '0x20c28')

调用函数

ShowAllHandle(FindFuzzyTopWindow(FuzzyWindowName='同花顺')[0])

得到一个全部对应关系的字典

python中spy++的使用超详细教程 

2.6 找到特定窗口的路径

因为句柄在不同电脑上的结果是不同的,所以我们要找到这个唯一的路

def FindHandlePath(TargetHandle, num):
 """
 寻找特定窗口的寻找路径
 :param TargetHandle: 窗口句柄(十六进制)
 :param num: 窗口所属index,在spy++内查看
 :return:
 ParentWindow:顶层窗口
 TargetPath:路径的index
 """
 AllPath = ShowAllHandle(pHandle=None, HandleList=[[None]], HandleDict=dict())
 key = tuple(list(show_window_attr(int(TargetHandle))) + [num])
 handlepath = [key]
 while True:
 key = AllPath[key]
 if not key:
 handlepath = handlepath[::-1]
 ParentWindow = handlepath[0]
 TargetPath = [(i[-1]) for i in handlepath[1:]]
 return ParentWindow, TargetPath
 handlepath.append(key)
  • 逻辑是找到全部层级的对应关系,然后反向搜索
  • 以“同花顺”的“买入”按钮为例,通过SPY++查找

python中spy++的使用超详细教程

我们得到其十六进制句柄为“0x40D98”,同时index为6

python中spy++的使用超详细教程

  • TargetHandle=0x40D98, num=6
  • 获取路径如下
>>> FindHandlePath(TargetHandle=0x40D98, num=6)
(('同花顺(v8.80.80) - 我的板块', 'Afx:400000:b:10003:6:d60ca7', 134184, '0x20c28', 308), 
[5, 0, 6])
  • 主窗体:同花顺(v8.80.80) - 我的板块
  • 5:第6个子窗体
  • 0:第1个子窗体
  • 6:第7个子窗体

2.7 根据路径来查找某个特定窗口的句柄

def FindTargetHandle(pHandle, WindowList):
 """
 递归寻找子窗口的句柄
 :param pHandle: 祖父窗口的完整句柄 (WindowName, ClassName, HwndPy, HwndSpy)
 :param WindowList: 子窗口列表
 :return: 目标窗口的完整属性
 """
 for i in range(len(WindowList)):
 pHandle = FindSubHandles(pHandle[2], index=WindowList[i])
 return pHandle
  • 现在
  • 我们已经有了某个窗体的查找路径,通过上述函数来查找其句柄我们的路径是:(('同花顺(v8.80.80) - 我的板块', 'Afx:400000:b:10003:6:d60ca7', 134184, '0x20c28', 308), [5, 0, 6])
  • 调用函数
>>> FindTargetHandle(('同花顺(v8.80.80) - 我的板块', 'Afx:400000:b:10003:6:d60ca7', 134184, '0x20c28', 308), [5, 0, 6])
('', 'Button', 265624, '0x40d98', 6)
  • 获得到了名为“Button”的窗体
  • 对比我们刚刚的结果,是正确的。

 2.8 根据句柄定位窗体

  • 这个按钮的十进制句柄为:265624
  • 调用函数GetWindowRect
>>> x,y,m,n = win32gui.GetWindowRect(265624)
>>> pyautogui.moveTo((x+m)/2, (y+n)/2)

此时鼠标会自动移动到这个窗体上


参考链接:
https://blog.csdn.net/qq_25408423/article/details/80884114
https://blog.csdn.net/seele52/article/details/17504925

到此这篇关于python中spy++的使用超详细教程的文章就介绍到这了!

Python 相关文章推荐
跟老齐学Python之玩转字符串(3)
Sep 14 Python
Python多层嵌套list的递归处理方法(推荐)
Jun 08 Python
对numpy.append()里的axis的用法详解
Jun 28 Python
python文件操作之批量修改文件后缀名的方法
Aug 10 Python
简单分析python的类变量、实例变量
Aug 23 Python
python求质数列表的例子
Nov 24 Python
python str字符串转uuid实例
Mar 03 Python
Python pandas如何向excel添加数据
May 22 Python
Python3合并两个有序数组代码实例
Aug 11 Python
解决python3.x安装numpy成功但import出错的问题
Nov 17 Python
python dir函数快速掌握用法技巧
Dec 09 Python
再谈python_tkinter弹出对话框创建
Mar 20 Python
Python Selenium破解滑块验证码最新版(GEETEST95%以上通过率)
Jan 29 #Python
详解pycharm的python包opencv(cv2)无代码提示问题的解决
Jan 29 #Python
如何用python开发Zeroc Ice应用
Jan 29 #Python
详解Pymongo常用查询方法总结
Jan 29 #Python
Python3使用tesserocr识别字母数字验证码的实现
Jan 29 #Python
Python爬取梨视频的示例
Jan 29 #Python
使用Python封装excel操作指南
Jan 29 #Python
You might like
如何使用Linux的Crontab定时执行PHP脚本的方法
2011/12/19 PHP
php基于curl扩展制作跨平台的restfule 接口
2015/05/11 PHP
浅析php静态方法与非静态方法的用法区别
2016/05/17 PHP
在Laravel框架里实现发送邮件实例(邮箱验证)
2016/05/20 PHP
解决PHP上传非标准格式的图片pjpeg失败的方法
2017/03/12 PHP
Yii 框架控制器创建使用及控制器响应操作示例
2019/10/14 PHP
PHP安全之register_globals的on和off的区别
2020/07/23 PHP
javascript 传统事件模型构造的事件监听器实现代码
2010/05/31 Javascript
Javascript 按位左移运算符使用介绍(
2014/02/04 Javascript
jquery数组封装使用方法分享(jquery数组遍历)
2014/03/25 Javascript
2则自己编写的jQuery特效分享
2015/02/26 Javascript
js获取html的span标签的值方法(超简单)
2016/07/26 Javascript
详解jQuery中的事件
2016/12/14 Javascript
Canvas实现放射线动画效果
2017/02/15 Javascript
js 倒计时(高效率服务器时间同步)
2017/09/12 Javascript
jquery在启动页面时,自动加载数据的实例
2018/01/22 jQuery
关于微信小程序登录的那些事
2019/01/08 Javascript
详解vue 路由跳转四种方式 (带参数)
2019/04/28 Javascript
原生javascript如何实现共享onload事件
2020/07/03 Javascript
基于JS实现快速读取TXT文件
2020/08/25 Javascript
写一个Vue loading 插件
2020/11/09 Javascript
javascript中导出与导入实现模块化管理教程
2020/12/03 Javascript
[27:53]2014 DOTA2华西杯精英邀请赛 5 24 NewBee VS iG
2014/05/26 DOTA
[01:32]寻找你心中的那团火 DOTA2 TI9火焰传递活动今日开启
2019/05/16 DOTA
Python多线程爬虫实战_爬取糗事百科段子的实例
2017/12/15 Python
python实现梯度下降算法
2020/03/24 Python
Python开发网站目录扫描器的实现
2019/02/21 Python
python爬虫 Pyppeteer使用方法解析
2019/09/28 Python
python中for循环变量作用域及用法详解
2019/11/05 Python
python3 pathlib库Path类方法总结
2019/12/26 Python
什么是python的列表推导式
2020/05/26 Python
python爬虫---requests库的用法详解
2020/09/28 Python
JavaScript+Canvas实现自定义画板的示例代码
2019/05/13 HTML / CSS
承诺书格式
2014/06/03 职场文书
动漫APP软件排行榜前十名,半次元上榜,第一款由腾讯公司推出
2022/03/18 杂记
vue使用element-ui按需引入
2022/05/20 Vue.js