目录
源码和工具下载
大漠综合工具->坐标和窗口信息抓取
在你的桌面上新建一个记事本用于后面的代码测试
完整项目源码
实现思路
介绍win32的基础思路
基本步骤
API介绍
代码实战
1. 获取窗口句柄的三种方法
2. 根据窗口句柄获取窗口信息
3. 通过句柄设置窗口
4. 激活窗口
5. 鼠标信息的获取
6. 鼠标点击事件
7. 键盘键位操作
8. 延时等待
9. 剪切板操作
10. 消息框与选择问答
11. 关闭窗口
N. 小结
总结
『python自动化』分享win32gui、cv2、easyocr等库相关的新手入门教程,目标是编写python程序进行自动化办公,解放双手。
欢迎关注 『python自动化』 系列,持续更新中
欢迎关注 『python自动化』 系列,持续更新中
如果安装win32gui库遇到了困难,可以参考下文安装。
【python自动化】01.安装配置库和环境之win32gui安装失败(保姆级图文)
源码和工具下载
大漠综合工具->坐标和窗口信息抓取
大漠综合工具获取句柄和窗口信息
1.用十字标记拖动到需要的窗口(注意拖到大窗口而不是小窗口,是整个记事本窗口而不是记事本的输入区域的小窗口)
2.绑定(方便后续的操作)
3.点击属性即可查看窗口信息,包括窗口的大小、坐标、16进制句柄
我的gitee仓库pywin32库自动操作键鼠
我们一般用的是16进制句柄,在这里查看
坐标和色点采集
注意这里的相对坐标和绝对坐标,我们绑定了窗口后默认把窗口左上角(0,0)视为参考标准。
在你的桌面上新建一个记事本用于后面的代码测试
完整项目源码
下载拿来即用
我的gitee仓库pywin32库自动操作键鼠
实现思路
介绍win32的基础思路
万物皆是窗口,首先获取窗口的句柄,然后再以此为基础对于窗口输送键鼠的命令。
基本步骤
获取窗口句柄->激活窗口->设置窗口大小位置->激活聊天输入框->输入内容
API介绍
下面的代码实战会详细介绍每个方法的参数,也可以访问pywin32的官方文档查看。(建议这么做,因为以后我们自学其他库都要经历查看文档这个过程)
官网网址
代码实战
1. 获取窗口句柄的三种方法
注意窗口类名, 窗口标题名两者必须至少有一个才能找到你想要的窗口,另一个可以缺省为None
法1:win32gui.FindWindow(窗口类名, 窗口标题名)#直接查找窗口
实例:win32gui.FindWindow(“Notepad”, None)
返回值:窗口的16进制句柄
import win32gui
#如果失败,要做好异常处理
#1.根据窗口标题获取句柄,通过标题查找,仅返回一个顶层窗口的句柄,不支持模糊查询
try:
# 获取窗口句柄
handle = win32gui.FindWindow("Notepad", None)#通过窗口标题获取窗口句柄
print("窗口句柄是:{}".format(handle))
except Exception as e:
print("窗口句柄获取失败:{}".format(e))
法2:win32gui.FindWindowEx(父窗口句柄, 查找窗口顺序, 窗口类名, 窗口标题名)#根据父窗口查找子窗口
实例:win32gui.FindWindowEx(0, 0, “Notepad”, None)
父窗口句柄:如果为 0,则假定为桌面窗口
查找窗口顺序:子窗口后按Z顺序搜索,可以为0搜索全部
返回值:查找得到的子窗口窗口的16进制句柄
#2.通过父窗口找子窗口,根据窗口类名和标题检索句柄,查找
# 参数
# 家长:PyHANDLE
# 将搜索其子窗口的窗口。如果为 0,则假定为桌面窗口。
# ChildAfter : PyHANDLE
# 子窗口后按Z顺序搜索,可以为0搜索全部
# 类名:PyResourceId
# 要查找的窗口类的名称或原子,可以是 None
# 窗口名称:字符串
# 要查找的窗口标题,可以是 None
import win32gui
try:
# 获取窗口句柄
# handle = win32gui.FindWindowEx(0, 0, "Notepad", '新建文本文档.txt - 记事本')
handle = win32gui.FindWindowEx(0, 0, "Notepad", None)
#注意,当你修改了记事本后标题名字前加上了一个变成了“新建文本文档.txt - 记事本”,所以这里可以填写None缺省,只用类名查找
print("窗口句柄是:{}".format(handle))
except Exception as e:
print("窗口句柄获取失败:{}".format(e))
法3:win32gui.WindowFromPoint((窗口x坐标, 窗口y坐标))#根据窗口坐标查找顶层符合坐标要求的一个窗口
实例:win32gui.WindowFromPoint((0, 0))
窗口坐标是每个窗口都会有的属性,但是这个方法只会查找顶层的那一个窗口,所以说改变置顶窗口就会改变通过这个方法获取的窗口句柄,所以不建议用。
返回值:查找得到的子窗口窗口的16进制句柄
#3.根据窗口左上角坐标获取句柄,(0, 0)只获取最顶层的左上角窗口,这种方法我个人不建议使用,因为顶层的窗口变化了,句柄就变化了
import win32gui
try:
# 获取窗口句柄
handle = win32gui.WindowFromPoint((0, 0))
print("窗口句柄是:{}".format(handle))
except Exception as e:
print("窗口句柄获取失败:{}".format(e))
2. 根据窗口句柄获取窗口信息
#获取窗口信息 (x,y坐标,还有宽度,高度)
原型:win32gui.GetWindowRect(窗口句柄)
实例:handleMessage = //代码效果参考:http://hnjlyzjd.com/hw/wz_24417.html
win32gui.GetWindowRect(handle)返回值:handleMessage是一个元组,包含四个元素,结构是(x坐标,y坐标,宽度,高度)
#获取窗口标题
原型:win32gui.GetWindowText(窗口句柄)
实例:win32gui.GetWindowText(handle)
返回值:字符串,窗口标题
#获取窗口类名
原型:win32gui.GetClassName(窗口句柄)
实例:win32gui.GetClassName(handle)
返回值:字符串,窗口类名
import win32gui
# 注意窗口句柄获取如果失败,要做好异常处理
try:
# 获取窗口句柄
handle = win32gui.FindWindowEx(0, 0, "Notepad", None)#
print("窗口句柄是:{}".format(handle))
except Exception as e:
print("窗口句柄获取失败:{}".format(e))
# 注意窗口信息获取如果失败,要做好异常处理
try:
# 获取窗口信息 (x,y坐标,还有宽度,高度)
handleMessage = win32gui.GetWindowRect(handle)#通过窗口句柄获取窗口信息
print("窗口 x,y坐标,还有宽度,高度是:{}".format(handleMessage))
# 获取窗口标题
title = win32gui.GetWindowText(handle)
print("窗口标//代码效果参考:http://hnjlyzjd.com/hw/wz_24415.html
题是:{}".format(title))# 获取窗口类名
class_name = win32gui.GetClassName(handle)
print("窗口类名是:{}".format(class_name))
except Exception as e:
print("窗口信息获取失败:{}".format(e))
3. 通过句柄设置窗口
#设置窗口信息
原型:win32gui.MoveWindow(窗口句柄, 窗口左边界,窗口上边界,窗口宽度,窗口高度,确定窗口是否被刷新)
实例:win32gui.MoveWindow(handle, 0, 0, 1280, 768, True)
返回值:None
import win32gui
# 注意窗口句柄获取如果失败,要做好异常处理
try:
# 获取窗口句柄
handle = win32gui.FindWindowEx(0, 0, "Notepad", None)#
print("窗口句柄是:{}".format(handle))
except Exception as e:
print("窗口句柄获取失败:{}".format(e))
try:
# 获取窗口信息 (x,y坐标,还有宽度,高度)
handleMessage = win32gui.GetWindowRect(handle)#通过窗口句柄获取窗口信息
print("窗口 x,y坐标,还有宽度,高度是:{}".format(handleMessage))
# 获取窗口标题
title = win32gui.GetWindowText(handle)
print("窗口标题是:{}".format(title))
# 获取窗口类名
class_name = win32gui.GetClassName(handle)
print("窗口类名是:{}".format(class_name))
# 设置窗口
# 参数:句柄,窗口左边界,窗口上边界,窗口宽度,窗口高度,确定窗口是否被刷新
win32gui.MoveWindow(handle, 0, 0, 1280, 768, True)
# 设置窗口后获取窗口信息,查看是否设置成功
handleMessage = win32gui.GetWindowRect(handle)#通过窗口句柄获取窗口信息
print("修改窗口后的窗口 x,y坐标,还有宽度,高度是:{}".format(handleMessage))
except Exception as e:
print("窗口信息获取失败:{}".format(e))
4. 激活窗口
#激活窗口
原型:win32gui.SetForegroundWindow(窗口句柄)
实例:win32gui.SetForegroundWindow(handle)
返回值:None
import win32gui
# 注意窗口句柄获取如果失败,要做好异常处理
try:
# 获取窗口句柄
handle = win32gui.FindWindowEx(0, 0, "Notepad", None)#
print("窗口句柄是:{}".format(handle))
# 将创建指定窗口的线程设置到前台,并且激活该窗口
win32gui.SetForegroundWindow(handle)
except Exception as e:
print("窗口句柄获取失败或是前台设置失败:{}".format(e))
5. 鼠标信息的获取
#获取鼠标位置
原型:win32api.GetCursorPos()
实例:point_position = win32api.GetCursorPos()
返回值:point_position 是一个元组,结构是(x坐标,y坐标)
#设置鼠标位置
原型:win32api.SetCursorPos((x坐标,y坐标))
实例:win32api.SetCursorPos((0, 0))
返回值:None
import win32gui
import win32api
# 注意窗口句柄获取如果失败,要做好异常处理
try:
# 获取窗口句柄
handle = win32gui.FindWindowEx(0, 0, "Notepad", None)#
print("窗口句柄是:{}".format(handle))
# 获取鼠标位置
point_position = win32api.GetCursorPos()
print("鼠标位置是:{}".format(point_position))
# 设置鼠标位置
win32api.SetCursorPos((0, 0))
# 获取鼠标位置
point_position = win32api.GetCursorPos()
print("设置后鼠标位置是:{}".format(point_position))
except Exception as e:
print("窗口句柄获取失败或是前台设置失败:{}".format(e))
6. 鼠标点击事件
鼠标点击分为点击和弹起2个过程。
#按下鼠标左键
原型:win32api.mouse_event(键位操作, 0, 0)
实例:win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)
返回值:None
#松开鼠标左键
原型:win32api.mouse_event(键位操作, 0, 0)
实例:win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0)
参数解读(dwFlags ,dx ,dy ,dwData ,dwExtraInfo)
dwFlags=0:双字,指定各种功能选项的标志
dx:double类型,鼠标的水平位置
dy : double类型,鼠标的垂直位置
dwData:double类型,标志特定参数
dwExtraInfo=0:double类型,与鼠标事件相关的附加数据
返回值:None
#键位表
MOUSEEVENTF_LEFTDOWN:表明接按下鼠标左键
MOUSEEVENTF_LEFTUP:表明松开鼠标左键
MOUSEEVENTF_RIGHTDOWN:表明按下鼠标右键
MOUSEEVENTF_RIGHTUP:表明松开鼠标右键
MOUSEEVENTF_MIDDLEDOWN:表明按下鼠标中键
MOUSEEVENTF_MIDDLEUP:表明松开鼠标中键
MOUSEEVENTF_WHEEL:鼠标轮移动,数量由data给出
import win32api
import win32con
import win32gui
# 注意窗口句柄获取如果失败,要做好异常处理
try:
# 获取窗口句柄
handle = win32gui.FindWindowEx(0, 0, "Notepad", None)#
print("窗口句柄是:{}".format(handle))
# 获取鼠标位置
point_position = win32api.GetCursorPos()
print("鼠标位置是:{}".format(point_position))
# 模拟鼠标在(1000, 500)位置进行点击操作
point = (1000, 500)
win32api.SetCursorPos(point)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)#按下鼠标左键
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0)#松开鼠标左键
# 获取鼠标位置
point_position = win32api.GetCursorPos()
print("鼠标位置是:{}".format(point_position))
except Exception as e:
print("窗口句柄获取失败或是前台设置失败:{}".format(e))
7. 键盘键位操作
键盘操作类似鼠标也分为按下和弹起2个过程。
有所区别的是,如果要输入内容,要先让鼠标激活输入框的焦点,所以要先点击一下。
同时也要注意一点,窗口操作最好加入一些延时,避免时序错误,导致出现先输入再激活焦点的错误,从而导致无法输入。
#按下按键
原型:win32api.keybd_event(键码, 硬件扫描码, 按下还是弹起的标志位, 与击键相关的附加的32位值)
实例:win32api.keybd_event(65, 0, KEYEVENTF_EXTENDEDKEY, 0)#按下A
实例:win32api.keybd_event(65, 0, 0, 0)#按下A
返回值:None
#弹起按键
原型:win32api.keybd_event(键码, 硬件扫描码, 按下还是弹起的标志位, 与击键相关的附加的32位值)
实例:win32api.keybd_event(65, 0, win32con.KEYEVENTF_KEYUP, 0)#松开A
实例:win32api.keybd_event(65, 0, 1, 0)#松开A
返回值:None
bVk:虚拟键码
bScan:硬件扫描码,一般设置为0即可
dwFlags:函数操作的一个标志位,如果值为KEYEVENTF_EXTENDEDKEY则该键被按下,也可设置为0即可,如果值为KEYEVENTF_KEYUP(也就是1)则该按键被释放
dwExtraInfo:定义与击键相关的附加的32位值,一般设置为0即可
import win32gui
import win32api
import win32con
# 注意窗口句柄获取如果失败,要做好异常处理
try:
# 获取窗口句柄
handle = win32gui.FindWindowEx(0, 0, "Notepad", None)#桌面窗口的所有子窗口检索类名"Edit",标题为None的窗口
print("窗口句柄是:{}".format(handle))
# 设置窗口
# 参数:句柄,窗口左边界,窗口上边界,窗口宽度,窗口高度,确定窗口是否被刷新
win32gui.MoveWindow(handle, 0, 0, 500, 500, True)
# 设置窗口后获取窗口信息,查看是否设置成功
handleMessage = win32gui.GetWindowRect(handle)#通过窗口句柄获取窗口信息
print("修改窗口后的窗口 x,y坐标,还有宽度,高度是:{}".format(handleMessage))
# 将创建指定窗口的线程设置到前台,并且激活该窗口
win32gui.SetForegroundWindow(handle)
#加入延时,否则可能会操作失败
print("如果没有下面以这一行代码,可能无法正常输入A B 字母,这就是延时等待的作用")
win32api.Sleep(1000)
#激活窗口输入栏
# 模拟鼠标在(246,217)位置进行点击操作,这个坐标主要是点击一下txt记事本的输入窗口,激活焦点
point = (246,217)
win32api.SetCursorPos(point)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)#按下鼠标左键
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0)#松开鼠标左键
#加入延时,否则可能会操作失败
win32api.Sleep(1000)
#在记事本中输入A B 字母
win32api.keybd_event(65, 0, 0, 0)#按下A
win32api.keybd_event(66, 0, 0, 0)#按下B
win32api.keybd_event(65, 0, win32con.KEYEVENTF_KEYUP, 0)#松开A
win32api.keybd_event(66, 0, win32con.KEYEVENTF_KEYUP, 0)#松开B
except Exception as e:
print("窗口句柄获取失败或是前台设置失败:{}".format(e))
8. 延时等待
这一节的内容和第7节类似,就是让大家试试看,如果不加入延时会发生什么,强调一下延时的作用。
#延时等待
原型:win32api.Sleep(等待毫秒)
实例:win32api.Sleep(1000)
返回值:None
import win32gui
import win32api
import win32con
# 注意窗口句柄获取如果失败,要做好异常处理
try:
# 获取窗口句柄
handle = win32gui.FindWindowEx(0, 0, "Notepad", None)#桌面窗口的所有子窗口检索类名"Edit",标题为None的窗口
print("窗口句柄是:{}".format(handle))
# 设置窗口
# 参数:句柄,窗口左边界,窗口上边界,窗口宽度,窗口高度,确定窗口是否被刷新
win32gui.MoveWindow(handle, 0, 0, 500, 500, True)
# 设置窗口后获取窗口信息,查看是否设置成功
handleMessage = win32gui.GetWindowRect(handle)#通过窗口句柄获取窗口信息
print("修改窗口后的窗口 x,y坐标,还有宽度,高度是:{}".format(handleMessage))
# 将创建指定窗口的线程设置到前台,并且激活该窗口
win32gui.SetForegroundWindow(handle)
#加入延时,否则可能会操作失败
print("如果没有下面以这一行代码,可能无法正常输入A B 字母,这就是延时等待的作用")
win32api.Sleep(1000)
#激活窗口输入栏
# 模拟鼠标在(246,217)位置进行点击操作
point = (246,217)
win32api.SetCursorPos(point)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)#按下鼠标左键
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0)#松开鼠标左键
#加入延时,否则可能会操作失败
print("如果没有下面以这一行代码,可能无法正常输入A B 字母,这就是延时等待的作用")
win32api.Sleep(1000)
#在记事本中输入A B 字母
win32api.keybd_event(65, 0, 0, 0)#按下A
win32api.keybd_event(66, 0, 0, 0)#按下B
win32api.keybd_event(65, 0, win32con.KEYEVENTF_KEYUP, 0)#松开A
win32api.keybd_event(66, 0, win32con.KEYEVENTF_KEYUP, 0)#松开B
except Exception as e:
print("错误:{}".format(e))
9. 剪切板操作
#打开剪切板
原型:win32clipboard.OpenClipboard()
实例:win32clipboard.OpenClipboard()
返回值:None
#剪切板置空
原型:win32clipboard.EmptyClipboard()
实例:win32clipboard.EmptyClipboard()
置剪切板为空,赋初始值是程序员的好习惯,注意任何数据一开始的样子
返回值:None