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之赋值,简单也不简单
Sep 24 Python
Python使用smtplib模块发送电子邮件的流程详解
Jun 27 Python
关于Python中异常(Exception)的汇总
Jan 18 Python
分享6个隐藏的python功能
Dec 07 Python
pycharm运行出现ImportError:No module named的解决方法
Oct 13 Python
Python运维开发之psutil库的使用详解
Oct 18 Python
python实现逐个读取txt字符并修改
Dec 24 Python
python3的UnicodeDecodeError解决方法
Dec 20 Python
Python实现手机号自动判断男女性别(实例解析)
Dec 22 Python
在django中form的label和verbose name的区别说明
May 20 Python
公认8个效率最高的爬虫框架
Jul 28 Python
python获取天气接口给指定微信好友发天气预报
Dec 28 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
晶体管来复再生式二管收音机
2021/03/02 无线电
Windows Apache2.2.11及Php5.2.9-1的安装与配置方法
2009/06/08 PHP
PHP 关于访问控制的和运算符优先级介绍
2013/07/08 PHP
php使用unset()删除数组中某个单元(键)的方法
2015/02/17 PHP
CodeIgniter删除和设置Cookie的方法
2015/04/07 PHP
PHP入门教程之面向对象的特性分析(继承,多态,接口,抽象类,抽象方法等)
2016/09/11 PHP
实例分析PHP中PHPMailer发邮件
2017/12/13 PHP
PHP实现可添加水印与生成缩略图的图片处理工具类
2018/01/16 PHP
javascript操作cookie的文章(设置,删除cookies)
2010/04/01 Javascript
Web开发者必备的12款超赞jQuery插件
2010/12/03 Javascript
纯javascript制作日历控件
2015/07/17 Javascript
JS如何实现文本框随文本的长度而增长
2015/07/30 Javascript
JS在一定时间内跳转页面及各种刷新页面的实现方法
2016/05/26 Javascript
JS简单测试循环运行时间的方法
2016/09/04 Javascript
深入理解JavaScript中的尾调用(Tail Call)
2017/02/07 Javascript
AngularJS 打开新的标签页实现代码
2017/09/07 Javascript
JS和JQuery实现雪花飘落效果
2017/11/30 jQuery
详解react内联样式使用webpack将px转rem
2018/09/13 Javascript
Vue.Draggable拖拽功能的配置使用方法
2020/07/29 Javascript
vue限制输入框只能输入8位整数和2位小数的代码
2019/11/06 Javascript
vue element-ui实现动态面包屑导航
2019/12/23 Javascript
python中将阿拉伯数字转换成中文的实现代码
2011/05/19 Python
Python实现图片转字符画的示例
2017/08/22 Python
python3利用venv配置虚拟环境及过程中的小问题小结
2018/08/01 Python
Python微信操控itchat的方法
2019/05/31 Python
Python selenium键盘鼠标事件实现过程详解
2020/07/28 Python
如何查看python关键字
2021/01/17 Python
button在IE6/7下的黑边去除方案
2012/12/24 HTML / CSS
匈牙利最大的健身制造商和销售商:inSPORTline
2018/10/30 全球购物
Kickers鞋英国官网:男士、女士和儿童鞋
2021/03/08 全球购物
市场营销专业个人求职信范文
2013/12/14 职场文书
火车来了教学反思
2014/02/11 职场文书
小学班级口号
2014/06/09 职场文书
2014年个人教学工作总结
2014/12/09 职场文书
2019年行政人事个人工作总结范本!
2019/07/19 职场文书
Python matplotlib绘制条形统计图 处理多个实验多组观测值
2022/04/21 Python