python 自动化学习(三) 句柄获取、模拟按键、opencv安装

news2024/11/30 10:41:25

一、什么是句柄

     句柄是在操作系统中的一种标识符,相当于我们每个人的身份证一样,句柄在电脑中也是有唯一性的,我们启动的每一个程序都有自己的句柄号,表示自己的身份

    为什么要说句柄,我们如果想做自动化操作时,肯定也不想程序占用了我们整个电脑,稍微操作一下程序步骤就乱掉了,更加希望自动化程序在运行的时候能够只针对某个窗口或者某个程序进行操作,即使我们把自动化的程序放入都后台时也不影响两边的操作,这里就需要用到句柄了

所需的包

#配置清华镜像源
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
pip config set global.trusted-host pypi.tuna.tsinghua.edu.cn
 
#安装依赖库
pip install pywin32

基本使用

#部分参考文档
https://huaweicloud.csdn.net/63803058dacf622b8df86819.html?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2~default~BlogCommendFromBaidu~activity-1-122498299-blog-111083068.pc_relevant_vip_default&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2~default~BlogCommendFromBaidu~activity-1-122498299-blog-111083068.pc_relevant_vip_default&utm_relevant_index=1

1、获取鼠标所在位置程序的句柄

import time
import win32api
import win32gui


time.sleep(2)

point = win32api.GetCursorPos()  #win32api.GetCursorPos 获取鼠标当前的坐标(x,y)

hwnd = win32gui.WindowFromPoint(point)  #查看坐标位置窗口的句柄

print(hwnd)  #输出句柄

如下图,我执行了3遍分别在执行后将鼠标放在文本、桌面、idea上面,返回了句柄ID

 

2、通过句柄获取类名

 我们每次关闭重新打开一个程序会发现句柄值变了,每次都从头找句柄就太麻烦了

每一个程序在开发之初就存在着一个叫"类名"的概念,类名和句柄每次变更不同,它在定义后几乎是不会发生变化的,所以我们最好是先找到一个程序的类名,后续直接通过类名找到句柄,然后在通过句柄进行真正所需要的操作

 vi main.py

import time
import win32api
import win32gui

# 通过句柄获取窗口类名
def get_clasname(hwnd):
    clasname = win32gui.GetClassName(hwnd)
    print('窗口类名:%s' % (clasname))
    return clasname



time.sleep(2)
point = win32api.GetCursorPos()
hwnd = win32gui.WindowFromPoint(point)

#查看窗口类名
get_clasname(hwnd)

 可以看到上面我们获取到了文档窗口的类名,现在开始我们直接通过类名去获取句柄

3、通过类名获取句柄

没有找到特定的方法,我们下面大概的思路就是先把主机上所有的句柄id都拿到,通过循环把所有句柄id的类名拿出来然后做对比,对的上的id都留在列表中,所以说如果开启了多个相同程序的窗口,我们也会获取到多个句柄

import time
import win32api
import win32gui

#获取当前主机上的所有句柄id
def get_all_windows():
    all_window_handles = []

    # 枚举所有窗口句柄,添加到列表中
    def enum_windows_proc(hwnd, param):
        param.append(hwnd)
        return True

    # 调用枚举窗口API
    win32gui.EnumWindows(enum_windows_proc, all_window_handles)

    return all_window_handles  #返回的是一个句柄id的列表


#查询传入的句柄id、类名
def get_title(window_handle, class_name):
    #查询句柄的类名
    window_class = win32gui.GetClassName(window_handle)

    #判断窗口类名是否和指定的类名相同,如果相同则返回该窗口句柄,否则返回空值
    if window_class == class_name:
        return window_handle

#遍历窗口句柄的所有子窗口
def get_child_windows(parent_window_handle):
    child_window_handles = []
    def enum_windows_proc(hwnd, param):
        param.append(hwnd)
        return True
    #win32gui.EnumChildWindows    遍历窗口句柄的所有子窗口
    win32gui.EnumChildWindows(parent_window_handle, enum_windows_proc, child_window_handles)
    return child_window_handles


# 根据标题查找窗口句柄
def find_hwnd_by_title(title):
    all_windows = get_all_windows()  #查询所有句柄
    matched_windows = []      #存放所有匹配类名的句柄id

    # 在所有窗口中查找标题匹配的窗口句柄
    for window_handle in all_windows:
        #get_title方法  检查传入句柄对应的类名和我们实际的类名是否对应
        window_title = get_title(window_handle, title)
        if window_title:
            matched_windows.append(window_title) #如果对应就写入列表

    # 如果没有匹配到,则在所有子窗口中查找标题匹配的窗口句柄
    if matched_windows:
        return matched_windows
    else:
        child_window_handles = []
        for parent_window_handle in all_windows:
            #不论子窗口是否有数据都追加到列表
            child_window_handles.extend(get_child_windows(parent_window_handle))
        for child_window_handle in child_window_handles:
            if get_title(child_window_handle, title):
                matched_windows.append(get_title(child_window_handle, title))
    return matched_windows

if __name__ == '__main__':
    hwnd = find_hwnd_by_title("Edit")
    print(hwnd)

 可以看到我们能够直接取到相同类名下所有已经打开的窗口句柄,这样我们甚至可以做个循环加多线程,来实现一个窗口并发的效果

二、模拟按键

上面我们已经拿到了文本文档的一个句柄信息,通过句柄我们可以做很多事情,最常见的就是模拟鼠标和键盘的按键操作,每个操作可能都较为细小琐碎,我们定义一个class类来存放

常见消息类型和标识

#官方参考
https://learn.microsoft.com/zh-cn/windows/win32/inputdev/wm-lbuttondown
消息类型作用消息标识作用
WM_MOUSEMOVE鼠标 移动移动通用左键右键标识
WM_RBUTTONDOWN鼠标 右键按下MK_RBUTTON左键按下
WM_RBUTTONUP鼠标 右键释放None释放时无需标识
WM_LBUTTONDOWN鼠标 左键按下MK_LBUTTON右键按下
WM_LBUTTONUP鼠标 左键释放None释放时无需标识

 当按键需要被按下时,需要先声明消息类型,然后标明按键状态
  如果鼠标按键需要被释放时,可以直接通过释放按钮来释放
  如果指定消息类型是移动时,可以当作已经声明了消息类型,可以直接使用按键标识

使用语法

#在win32api下有个函数PostMessage,是用来与windows api交互的,参数如下
1、要发送消息的目标窗口的句柄
2、发送的消息类型
3、以及消息的参数 


win32api.PostMessage(句柄id, 消息类型, 消息标识, 具体的坐标(x,y))

获取目标坐标

#获取坐标
time.sleep(3)
print(win32api.GetCursorPos())

返回

(328, 250)

 

鼠标按键案例

      下面定义了一个类,先去接受我们上面获取到的句柄id,在使用鼠标按键的时候调用win32api.PostMessage函数 去发送给句柄所在的窗口按键信息

   在左右键按下的时候才需要定义标识,比如模拟左键时会使用WM_LBUTTONDOWN和MK_LBUTTON  ,而松开时使用WM_LBUTTONUP和None

   变量pos 是只鼠标按键的坐标,需要通过win32api.MAKELONG 转换数据类型后才能调用


#声明鼠标操作的类
class WinMouse(object):

    #初始化函数,接受传入的句柄id
    def __init__(self, handle_num: int):
        self.handle = handle_num  

    #鼠标左键按下
    def left_button_down(self, pos):
            win32api.PostMessage(self.handle, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, pos)

    #鼠标左键释放
    def left_button_up(self, pos):
        win32api.PostMessage(self.handle, win32con.WM_LBUTTONUP, None, pos)



if __name__ == '__main__':
    hwnd = find_hwnd_by_title("Edit")   #通过类名获取句柄
    bd = WinMouse(hwnd[0])              #实例化WinMouse 类,传入句柄值

    pos = win32api.MAKELONG(328, 250)   #将正常的x,y坐标值转换为特定的数据结构,
                                       #给win32api.PostMessage调用

    #按下、等待1s、松开
    bd.left_button_down(pos)  
    time.sleep(1)             
    bd.left_button_up(pos)    

可以看到在下图中,我们运行程序后,不论文本文档是否在前台还是后台,哪怕被遮挡住后也会照常进行鼠标点击(数字太多看不清,大致就是我把鼠标放到末尾,程序在我上面取坐标的地方点一下左键)

其他按键补全

    #按下鼠标左键并移动
    def mouse_move(self, pos):
        win32api.PostMessage(self.handle, win32con.WM_MOUSEMOVE, win32con.MK_LBUTTON, pos)

    #按下鼠标右键并移动
    def right_button_move(self, pos):
        win32api.PostMessage(self.handle, win32con.WM_MOUSEMOVE, win32con.MK_RBUTTON, pos)

    #指定坐标按下右键
    def right_button_down(self, pos):
        win32api.PostMessage(self.handle, win32con.WM_RBUTTONDOWN, win32con.MK_RBUTTON, pos)
    #右键释放
    def right_button_up(self, pos):
        win32api.PostMessage(self.handle, win32con.WM_RBUTTONUP, None, pos)

    #模拟左键双击
    def left_double_click(self, x_pos:int, y_pos:int, click=2, wait=0.4):
        wait = wait / click  #click 表示点击次数,wait是的等待时间,意思是双击的间隔
        point = win32api.MAKELONG(x_pos, y_pos)
        for i in range(click):
            self.left_button_down(point)
            time.sleep(wait)
            self.left_button_up(point)
    #右键双击
    def right_doubleClick(self, x, y, click=2, wait=0.4):
        wait = wait / click
        pos = win32api.MAKELONG(x, y)
        for i in range(click):
            self.right_button_down(pos)
            time.sleep(wait)
            self.right_button_up(pos)

按键组合函数

上面用一个按左键都要好几行,我们这里在给封装一下

    #让他可以直接接收x,y坐标,wait是松开按键的间隔,一般默认即可
    #左键单击
    def left_click(self, x_pos:int, y_pos:int, wait=0.2):
        point = win32api.MAKELONG(x_pos, y_pos)
        self.left_button_down(point)
        time.sleep(wait)
        self.left_button_up(point)

    #右键单击
    def right_click(self, x_pos:int, y_pos:int, wait=0.2):
        point = win32api.MAKELONG(x_pos, y_pos)
        self.right_button_down(point)
        time.sleep(wait)
        self.right_button_up(point)

    #模拟左键双击
    def left_double_click(self, x_pos:int, y_pos:int, click=2, wait=0.4):
        wait = wait / click  #click 表示点击次数,wait是的等待时间,意思是双击的间隔
        point = win32api.MAKELONG(x_pos, y_pos)
        for i in range(click):
            self.left_button_down(point)
            time.sleep(wait)
            self.left_button_up(point)
    #右键双击
    def right_doubleClick(self, x, y, click=2, wait=0.4):
        wait = wait / click
        pos = win32api.MAKELONG(x, y)
        for i in range(click):
            self.right_button_down(pos)
            time.sleep(wait)
            self.right_button_up(pos)

鼠标滑动拖拽

我们左右键按住到目标坐标后松开的操作稍微复杂一些,单独说下,大致的思路如下

添加偏移值

 vi main.py

#计算鼠标从起始点到目标点的偏移过程
def getPointOnLine(start_x, start_y, end_x, end_y, ratio):
    x = ((end_x - start_x) * ratio) + start_x
    y = ((end_y - start_y) * ratio) + start_y
    return int(round(x)), int(round(y))


class WinMouse(object):

    def __init__(self, handle_num: int, num_of_steps=80): #添加num_of_steps=80
        self.handle = handle_num
        self.num_of_steps = num_of_steps  #添加偏移值

添加左右键拖动方法

    #模拟点击并拖拽目标,接受两对坐标值
    def left_click_move(self, x1:int, y1:int, x2:int, y2:int, wait=2):
        point1 = win32api.MAKELONG(x1, y1)
        self.left_button_down(point1)  #起始点按下鼠标左键
        #获取我们在init初始化时定义的偏移值
        steps = self.num_of_steps

        #调用我们上面的方法返回具体,循环0-80的值
        #你看这里的循环值是80,也就说会做80次循环操作
        #我们传入了起始坐标和目标坐标,而i / steps就相当于起始到结束的偏移位置
        #可以理解为从左上角到右下角的点
        points = [getPointOnLine(x1, y1, x2, y2,  i / steps) for i in range(steps)]
        points.append((x2, y2))
        wait_time = wait / steps
        unique_points = list(set(points))
        unique_points.sort(key=points.index)
        for point in unique_points:
            x, y = point
            point = win32api.MAKELONG(x, y)
            self.mouse_move(point)
            time.sleep(wait_time)
            self.left_button_up(point)
    #右键单击并滑动批量勾选(与上方函数同理)
    def right_click_move(self, start_x, start_y, end_x, end_y, wait=2):
        pos = win32api.MAKELONG(start_x, start_y)
        self.right_button_down(pos)
        steps = self.num_of_steps
        points = [getPointOnLine(start_x, start_y, end_x, end_y, i / steps) for i in range(steps)]
        points.append((end_x, end_y))
        time_per_step = wait / steps
        distinct_points = list(set(points))
        distinct_points.sort(key=points.index)
        for point in distinct_points:
            x, y = point
            pos = win32api.MAKELONG(x, y)
            self.right_button_move(pos)
            time.sleep(time_per_step)
        self.right_button_up(pos)

拖动有时候突然就不好使了,不清楚原因,稍后补上

三、准备opencv环境

安装模块

pip install opencv-python
pip install pyautogui
pip install pillow
pip install opencv-contrib-python

我这边在安装上opencv-python 后调用cv2下任意方法都提示报黄,没有代码提示,下面列出解决方法

(venv) PS C:\Users\Administrator\IdeaProjects\test> pip install opencv-python
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Requirement already satisfied: opencv-python in c:\users\administrator\ideaprojects\test\venv\lib\site-packages (4.7.0.72)
Requirement already satisfied: numpy>=1.21.2 in c:\users\administrator\ideaprojects\test\venv\lib\site-packages (from opencv-python) (1.24.3)

我们在安装成功opencv-python模块后会返回一个安装路径,登录这个路径,进入cv2的目录下,将cv2.pyd 文件放到下面的路径下,重启编辑器即可

c:\users\administrator\ideaprojects\test\venv\lib\site-packages

 

测试语句

import cv2
# 加载一张图片
img = cv2.imread('11.png', 1)   #脚本文件旁边自行准备一个图片

# 显示图片
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/572060.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据库复习】第六章 关系数据理论 2

若R∈BCNF 所有非主属性对每一个码都是完全函数依赖 所有的主属性对每一个不包含它的码,也是完全函数依赖 没有任何属性完全函数依赖于非码的任何一组属性 多值依赖 Teaching具有唯一候选码(C,T,B), 即全码, ∈3NF …

JAVA商城源码-B2B2C商城系统-独立部署,一套源码终身可用

在现在电商迅速占领市场的时代里,选择开发商城系统已经成为了一种趋势,现在开发搭建商城系统有很多编程语言可以选择,目前在电商里市面上受到很多商家企业的喜爱的便是Java商城系统,那为什么要选择Java电商系统呢? 1、…

linuxOPS基础_服务器构成

服务器的重要结构组成 家用电脑组成: CPU、主板、内存条、显卡、硬盘、电源、风扇、网卡、显示器、机箱、键盘鼠标等等。 CPU CPU是电脑的大脑, CPU发展史: 32 位CPU:最大的内存寻址地址2^32,大约4G的大小。 CP…

js 常用函数 push()、pop()、shift()、unshift()、slice()、splice() 等

文章目录 1. join() 函数2.push() 函数3. pop() 函数4.shift() 函数5.unshift() 函数6.sort() 函数7. reverse() 函数8. concat() 函数9.slice() 函数10. splice() 函数11. indexOf() & lastIndexOf() 函数 最近对前端一些函数的用法还不是很熟悉,有一些函数容易…

手持式网络性能测试仪应用于哪些领域及可以完成什么工作?

首先明辰智航国产网络一点通有千兆和万兆以手持式网络性能测试仪,两款仪器可以应用于以下领域: 电信运营商:用于测试网络质量、信号强度、带宽、时延、丢包率等参数,以便优化网络性能和提高用户满意度。 企业网络管理&#xff1a…

【什么是iMessage苹果推?】什么是苹果推信?什么是苹果推?

挑选得当的IM推送平台:选择合用于PC真个IM推送平台 开辟或集成API:依照所选平台的开发文档,利用响应的编程语言(如Python、Java等)开发或集成API,以便与平台举行交互和节制。API可用于建立、办理和发送消息…

STM32F103 USB实现虚拟串口

STM32F103 USB实现虚拟串口 最近买了一个STM32F103C8T6最小核心板,使用CubeIDE无法识别该芯片,发现该芯片的flash是128Kbytes,ST的标准库是64Kbytes,奇怪啊!也许是国产替代的,国产化太先进了,导…

CCIG:智能文档处理「新未来」

文章目录 ⭐️ CCIG大会简介⭐️ 领先世界的智能文档处理技术🌟 智能图像处理:为文字识别 "增质提效" 筑基✨ 切边增强 - 提升文档图像质量✨ 弯曲矫正 - 解决图像畸变问题✨ 去摩尔纹 - 保证图像信息完整 🌟 图像预处理整体效果展…

汇编基础知识

1.汇编工程流程: 汇编指令--->编译器--->机器码--->计算机 2.汇编语言组成: 1.汇编指令 2.伪指令 3.其他符号 3.存储器: 存放指令与数据的容器,也叫内存. 存储器被划分为多个单元,并且从0开始按钮顺序编号,这些编号视为存储器的存储单元的地址. 4.指令与…

《Cocos Creator游戏实战》老虎机抽奖效果实现思路

在线体验地址 Cocos Creator | SlotMachine Cocos Store 购买地址(如果没有显示,那就是还在审核): https://store.cocos.com/app/detail/4958微店购买地址: https://weidian.com/item.html?itemID6338406353运行效果…

平板用什么远程操控电脑

现在的第三方专业远程软件大部分支持跨平台连接,要使用平板电脑远程控制电脑,还是很简单的。一般来说按照以下步骤操作即可。 确保两台设备都连接到互联网 确保您要控制的电脑和平板电脑都通过 Wi-Fi 或移动数据连接到互联网。 安装远程控制应用程序 …

设计事务所项目管理指南

在数字化的浪潮下,各行各业都面临着升级转型的问题。对设计团队而言,传统的管理方式已经无法满足日益前进的团队需求。 设计事务所可能存在的管理问题: 1,项目过程中信息流通慢,成员工作进度无法及时同步; …

结构型设计模式01-装饰模式

✨作者:猫十二懿 ❤️‍🔥账号:CSDN 、掘金 、个人博客 、Github 🎉公众号:猫十二懿 装饰模式 1、 问题引入 要实现一个简单的个人形象系统,使用控制台输出的形式,简单说明搭配着装 Person pa…

【快应用】响应式布局适配横竖屏或折叠屏

【关键词】 响应式布局、折叠屏、横竖屏 【问题背景】 当前开发者在开发快应用时,往往将designWidth设置为设备屏幕的宽度,这时,应用的内容会随着设备宽度的变大而拉伸显示,导致在大屏、横屏、折叠屏展开时显示效果不好。 在折…

PMP考试应该要如何备考?如何短期通过PMP?

我从新考纲考完下来,3A通过了考试,最开始也被折磨过一段时间,但是后面还是找到了方法,也算有点经验,给大家分享一下吧。 程序猿应该是考PMP里面人最多的,毕竟有一个30大坎,大部分人还是考虑转型…

微信小程序button按钮设置宽度无效

button按钮设置宽度无效 背景: 在开发小程序的过程中,遇到了button按钮设置宽度无效的问题 微信客户端 7.0 开始,UI 界面进行了大改版。小程序也进行了基础组件的样式升级,涉及的组件有 button,icon,radio,checkbox,switch,sli…

手把手教你在昇腾平台上搭建PyTorch训练环境

PyTorch是业界流行的深度学习框架,用于开发深度学习训练脚本,默认运行在CPU/GPU上。在昇腾AI处理器上运行PyTorch业务时,需要搭建异构计算架构CANN(Compute Architecture for Neural Networks)软件开发环境&#xff0c…

《花雕学AI》36:探索Aski AI——集成问答、写作和绘画功能的强大AI平台

引言:人工智能是当今时代的最热门和最有前途的技术之一,它可以帮助人类解决各种复杂和有趣的问题,提高生活和工作的效率和质量。然而,人工智能的应用还面临着许多挑战和局限,比如数据的稀缺和质量、算法的复杂性和可解…

CompletableFuture详解-初遇者-很细

目录 一、创建异步任务 1. supplyAsync 2. runAsync 3.获取任务结果的方法 二、异步回调处理 1.thenApply和thenApplyAsync 2.thenAccept和thenAcceptAsync 2.thenRun和thenRunAsync 3.whenComplete和whenCompleteAsync 4.handle和handleAsync 三、多任务组合处理 1…

Git的安装及基础命令

一. 安装Git 首先请前往Git官网去下载最新的安装包:https://git-scm.com/download/win 运行下载好的 .exe 文件,一路next即可。 右击桌面出现以下两个就算是成功。 安装完成后,需要设定用户名和邮箱来区分不同的用户。右击屏幕,选择“Git Bash Here”…