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种方法
Nov 22 Python
Python日志模块logging简介
Apr 13 Python
在Python中使用全局日志时需要注意的问题
May 06 Python
KMP算法精解及其Python版的代码示例
Jun 01 Python
Python将图片批量从png格式转换至WebP格式
Aug 22 Python
python的变量与赋值详细分析
Nov 08 Python
python机器人行走步数问题的解决
Jan 29 Python
python3 flask实现文件上传功能
Mar 20 Python
浅谈python元素如何去重,去重后如何保持原来元素的顺序不变
Feb 28 Python
Python实现Wordcloud生成词云图的示例
Mar 30 Python
浅析Python 多行匹配模式
Jul 24 Python
python反扒机制的5种解决方法
Feb 06 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
destoon实现VIP排名一直在前面排序的方法
2014/08/21 PHP
php模拟实现斗地主发牌
2020/04/22 PHP
代码生成器 document.write()
2007/04/15 Javascript
Convert Seconds To Hours
2007/06/16 Javascript
JQuery Tips(2) 关于$()包装集你不知道的
2009/12/14 Javascript
javascript中"/"运算符常见错误
2010/10/13 Javascript
正负小数点后两位浮点数实现原理及代码
2013/09/06 Javascript
JS实现OCX控件的事件响应示例
2014/09/17 Javascript
ECMAScript6块级作用域及新变量声明(let)
2015/06/12 Javascript
js钢琴按钮波浪式图片排列效果代码分享
2015/08/26 Javascript
jQuery控制frames及frame页面JS的方法
2016/03/08 Javascript
深入浅析Bootstrap列表组组件
2016/05/03 Javascript
jQuery实现简洁的轮播图效果实例
2016/09/07 Javascript
Vue-cli-webpack搭建斗鱼直播步骤详解
2017/11/17 Javascript
小程序自定义组件实现城市选择功能
2018/07/18 Javascript
mpvue将vue项目转换为小程序
2018/09/30 Javascript
[33:17]OG vs VGJ.T 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
Python面向对象class类属性及子类用法分析
2018/02/02 Python
Python实现按当前日期(年、月、日)创建多级目录的方法
2018/04/26 Python
用Python编写一个简单的CS架构后门的方法
2018/11/20 Python
python的sorted用法详解
2019/06/25 Python
python join方法使用详解
2019/07/30 Python
Python二次规划和线性规划使用实例
2019/12/09 Python
Python 实现3种回归模型(Linear Regression,Lasso,Ridge)的示例
2020/10/15 Python
新西兰珠宝品牌:Michael Hill
2017/09/16 全球购物
ETO男装官方网店:ETO Jeans
2019/02/28 全球购物
英国儿童设计师服装的领先零售商:Base
2019/03/17 全球购物
您熟悉ORM(Object-Relation Mapping)吗?请谈谈您所理解的ORM
2016/02/08 面试题
材料物理专业大学毕业生求职信
2013/10/15 职场文书
2014年党员加强作风建设思想汇报
2014/09/15 职场文书
企业法人代表授权委托书
2014/10/02 职场文书
员工家属慰问信
2015/03/24 职场文书
毕业论文致谢部分怎么写
2015/05/14 职场文书
用Python提取PDF表格的方法
2021/04/11 Python
vue3使用vue-router的完整步骤记录
2021/06/20 Vue.js
教你如何用Python实现人脸识别(含源代码)
2021/06/23 Python