本博客仅为个人学习使用,是看大佬视频做的笔记,侵权可联系作者删除~~
pywinauto的安装,在cmd命令行窗口直接输入pip install pywinauto即可
1、通过进程号或句柄连接
from pywinauto.application import Application
# 通过pywinauto去连接已经打开的应用程序# 通过进程号进行连接,可以使用ViewWizard查看进程号等信息# 通过PID连接,需要先打开程序# app = Application('uia').connect(process=6136)# print(app)# 通过窗口句柄进行连接# 同样需要先打开程序,然后使用ViewWizard获取句柄,句柄是动态的
app = Application('uia').connect(handle=131914)'''
这个uia,在启动navicat的时候需要,不然报错;
启动文本文件的时候不用,不然找不到弹出的窗口
初步推论:win32(可不填)在自带程序中使用,其他需下载安装等程序使用uia
Win32 API(backend="win32") - 现在的默认后端
MFC,VB6,VCL,简单的WinForms控件和大多数旧的遗留应用程序,win32
MS UI Automation(backend="uia")
WinForms,WPF,商店应用,Qt5,浏览器,navicat
注意:Chrome --force-renderer-accessibility在启动前需要cmd标志。
由于comtypes Python库限制,不支持自定义属性和控件。'''print(app)
2、通过路径打开app并选择窗口
from pywinauto.application import Application
# 启动navicat,路径也可以通过ViewWizard工具获取
app = Application('uia').start(r'E:\Navicat Premium 15\navicat.exe')# 方式一 app[类名/标题]# 使用窗口类名来选择窗口# dlg = app["TNavicatMainForm"]# 使用窗口标题来选择窗口
dlg = app['Navicat Premium']
dlg.maximize()# 方式二 app.窗口类名# dlg = app.TNavicatMainForm# 打印窗口中所有的控件# dlg.print_control_identifiers()
3、选择控件
from pywinauto.application import Application
# 启动navicat
app = Application('uia').start(r'D:\tools\Navicat Premium 15\navicat.exe')# 通过窗口标题选择窗口
dlg = app['Navicat Premium']# dlg.print_control_identifiers()# 选择控件 ---- 选择当前窗口的各级菜单# 方式一# menu = dlg.Menu# print(menu.print_control_identifiers())# 方式二
menu = dlg['Menu']# print(menu.print_control_identifiers())# ------报错------------# file = dlg['Menu']['文件']# print(file.print_control_identifiers())# 方式三# menu下面的中括号显示的是['MenuItem', '文件MenuItem', '文件', 'MenuItem0', 'MenuItem1']# 文件是第一个子菜单,根据菜单名查找就好,不用管中括号里面有几个file= menu.child_window(title="文件", control_type="MenuItem")file.print_control_identifiers()
4、选择菜单项、获取文本等
from pywinauto.application import Application
# 启动navicat,选择应用程序
app = Application('uia').start(r'D:\tools\Navicat Premium 15\navicat.exe')# 通过窗口标题选择窗口
dlg = app['Navicat Premium']# 选择窗口的菜单
menu = dlg['Menu']# 选择菜单项:文件file= menu.child_window(title="文件")# 查看控件类型:wrapper_object# print(dlg.wrapper_object()) # Dialog 对话框# print(menu.wrapper_object()) # Menu 菜单# print(file.wrapper_object()) # MenuItem 菜单项# dir 查看对象所支持的方法# print(dir(dlg.wrapper_object()))# 控件的文本内容获取:texts --- 得到的是列表print(file.texts())# 获取子元素:children# print(dlg.children())# 获取菜单的子元素# print(menu.children())# print(file.children())# 获取控件的类名print(menu.class_name())# 获取控件的属性、返回的字典print(menu.get_properties())
5、截图处理
from pywinauto.application import Application
# 启动navicat
app = Application('uia').start(r'E:\Navicat Premium 15\navicat.exe')# 通过窗口标题选择窗口
dlg = app['Navicat Premium']
menu = dlg['Menu']## # 选择菜单项:文件file= menu.child_window(title="文件")# 截图窗口:
pic = dlg.capture_as_image().save('01.png')print(pic)
6、菜单的相关操作
# 点击菜单项用click_input(),点击按钮可直接用click()from pywinauto.application import Application
app = Application('uia').start(r'E:\Navicat Premium 15\navicat.exe')
dlg = app['Navicat Premium']
menu = dlg['Menu']file= menu.child_window(title="文件", control_type="MenuItem")# -------菜单控件和相关操作---------------# 获取菜单的子菜单项# print(menu.items())# 通过下标去选择菜单项:item_by_path# m = menu.item_by_index(1)# print(m)# 通过路径去选择菜单项:item_by_path ,相对路径# m = menu.item_by_path('查看')# print(m)# 通过路径去选择菜单项:item_by_path ,相对路径# m = menu.item_by_path('文件->导入连接...')# print(m)# ----- 菜单项的操作方法-----# 获取子菜单项:items# print(file.items())# 点击菜单项的方法:click_input# 注意:先点击文件,然后点击新建连接file.click_input()
menu.item_by_path('文件->新建连接').click_input()
7、等待机制
from pywinauto.application import Application
app = Application('uia').start(r'E:\Navicat Premium 15\navicat.exe')
dlg = app['Navicat Premium']
menu = dlg['Menu']# menu.print_control_identifiers()file= menu.child_window(title="文件", control_type="MenuItem")# 点击文件file.click_input()# 点击新建连接
menu.item_by_path('文件->新建连接').click_input()'''
等待机制一
wait方法: 等待窗口处于某个状态
参数:
wait_for :等待的状态(状态有以下几种)
exists: 表示该窗口是有效的句柄
visible:表示该窗口未隐藏
enabled:表示未禁用窗口
ready:表示该窗口可见并启用
active:表示该窗口处于活动状态
timeout : 超时时间
retry_interval :重试时间间隔
'''# 选择新建连接的窗口
new_dlg = app['新建连接']# 等待窗口处于可见状态# new_dlg.wait(wait_for="ready", timeout=10, retry_interval=1)# print('等待通过,当前新建连接窗口处于可见状态')'''
等待机制二
Wait_not方法: 等待窗口不处于某个特定状态
参数:
wait_for_no :等待的状态(状态有以下几种)
exists: 表示该窗口是有效的句柄
visible:表示该窗口未隐藏
enabled:表示未禁用窗口
ready :表示该窗口可见并启用
active:表示该窗口处于活动状态
timeout : 超时时间
retry_interval :重试时间间隔
'''
new_dlg.wait_not(wait_for_not="ready", timeout=10, retry_interval=1)print('等待通过,当前新建连接窗口处于不可见状态')'''
等待机制三
wait_cpu_usage_lower 方法
等待该进程的cup的使用率低于某个阀值
注意:此方法仅适用于整个应用程序进程,不适用于窗口/元素。
参数:
threshold :该进程cup占用率
timeout : 超时时间
retry_interval :重试时间间隔
'''
app1 = Application().connect(process=8728)
app1.wait_cpu_usage_lower(threshold=5, timeout=5, usage_interval=1)print('等待通过,当前该进程cpu占用了低于1%')
8、timing相当于显示等待
from pywinauto.timings import wait_until
'''
timings模块
wait_until方法:
参数:
Timeout: 超时时间
retry_interval 重试时间
func 执行的函数
value 比较的值
Op 比较方式函数(默认为相等)
args 给执行函数传位置参数
kwargs 给执行函数传关键字参数
''''''
全局计时变量值的设置方法
Timings.defaults() :将全局计时设为默认值
Timings.slow() :将所有时间加倍(使脚本执行速度降低约2倍)
Timings.fast(): # 将所有计时除以2 (快2倍)
'''
i =0defwork():global i
i +=1print('当前i的值为:', i)return i
# 等待work返回的结果为5,继续往下执行# wait_until(10, 1, work, 5)# print('等待通过')
wait_until(10,1, work,15)print('等待超时')
9、编辑类控件的基本操作
from pywinauto.application import Application
from pywinauto.keyboard import send_keys
# 选择应用程序
app = Application('win32').start('notepad.exe')# app = Application('uia').start('notepad.exe')# 不使用uia,因为文本文件是自带程序# 选择窗口
dlg = app['无标题 - 记事本']# dlg.print_control_identifiers()# 选择窗口中的控件
dlg['Edit'].type_keys("hello world,哈哈?为什么空格不能显示为什么??")# menu.print_control_identifiers()# 为啥不用点击编辑,就可以直接点击替换啊?奇怪# edit_btn = menu.child_window(title="编辑(E)", control_ty pe="MenuItem")# edit_btn.click_input()# 写法二、dlg.menu_select('编辑(E)->替换(R)') 有时候会不可用
dlg.menu_select('编辑(E)->替换(R)')# 写法一、menu.item_by_path('编辑(E)->替换(R)').click_input()# 切换到替换的窗口
replace = app['替换']
replace.print_control_identifiers()# 输入查找内容
replace['Edit1'].type_keys('哈')# 输入需要替换的内容
replace['Edit2'].type_keys('嗯哼')# 点击全部替换
replace['Button3'].click_input()# 点击取消按钮
replace['Button4'].click_input()
10、模拟键盘操作
from pywinauto.keyboard import send_keys
# send_keys("{F1}")# 通过按键打开cmd,输入python
send_keys('{VK_LWIN}cmd{VK_RETURN}{VK_RETURN}')
send_keys('python')
send_keys('{VK_RETURN}')
11、键盘修饰符的使用
from pywinauto.keyboard import send_keys
'''
"+" --> 按Shift
"^" --> 按CtrI
"%" --> 按Alt
"^s" --> 按CtrI+S进行保存的操作
'''
send_keys('^a')
send_keys('^c')
send_keys('^v')
send_keys('^v')
send_keys("%+{VK_F10}")
12、模拟鼠标操作
from pywinauto import mouse
# 鼠标单击(默认左键)# 默认button左键点击,coords参数为像素,可用截图查看# mouse.click(button='left',coords=(485, 18))# 鼠标右键# mouse.right_click(coords=(1060, 580))# 鼠标双击(默认双击左键)# mouse.double_click(button='left', coords=(48, 176))# 点击鼠标中键# mouse.wheel_click(coords=(500, 1000))# 按下鼠标(会一直按住,移动鼠标即可实现拖动效果)# mouse.press(coords=(80, 20))# 释放鼠标(位置A按下,位置B释放,即可实现拖动到位置B的效果)# mouse.release(coords=(500, 1000))# 滑动鼠标滚轮(wheel_dist滚轮滚几圈,正数向上滚,负数向下滚)# mouse.scroll(coords=(1000, 500),wheel_dist=3)# 移动鼠标位置--将鼠标移动到某个位置# mouse.move(coords=(0, 0))for i inrange(0,1000,50):
mouse.move(coords=(i, i))
13、系统提示区(右下角任务栏)的操作
from pywinauto import Application
app = Application("uia").connect(handle=65722)# 不知道为什么这行报错,跟老师代码一模一样的
app["任务栏"].print_control_identifiers()# 到任务栏中选择用户提示通知区域,点击QQ
qq = app["任务栏"].child_window(title="QQ: 慎\r\n声音: 关闭\r\n消息提醒框: 关闭\r\n会话消息: 任务栏头像闪动", control_type="Button")
qq.click()
14、隐藏通知区域的操作
from pywinauto import Application
app = Application("uia").connect(handle=65722)
task = app["任务栏"].child_window(title="通知 V 形", auto_id="1502", control_type="Button")
task.click()#选择通知溢出的窗口,然后就可以进行相关的操作# 隐藏区域需要先点击然后对应的窗口才会显示,可以使用inspect.exe工具
app["通知溢出"].print_control_identifiers()
app["通知溢出"]["Windows 安全中心"].click()
15、pywinauto结合selenium实现文件上传
from selenium import webdriver
from pywinauto.keyboard import send_keys
import pywinauto
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get(r'http://XXX.baidu.com/uploadimg?picIdFlag=pic02&category_id=1')# 点击上传图片按钮
driver.find_element(By.ID,'btnSelect').click()# 上传图片弹出的窗口需要用pywinauto选择图片
app = pywinauto.Desktop()
dlg = app["打开"]
dlg.print_control_identifiers()# 选中文件地址输入的工具框,# 因为不是输入框不能直接输入,需要通过键盘输入# 输入文件地址
dlg['Toolbar3'].click()
send_keys("图片{VK_RETURN}")# 输入图片名
dlg['Edit'].click()
send_keys("壁纸.jpg{VK_RETURN}")
16、pywinauto实现多文件上传及代码封装
# Button类型的就可以直接调用click()from selenium import webdriver
from pywinauto.keyboard import send_keys
import pywinauto
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get(r'http://XXXX.baidu.com/uploadimg?picIdFlag=pic02&category_id=1')# 点击上传图片按钮
driver.find_element(By.ID,'btnSelect').click()defupload_img(file_path,file,*args):# 上传图片弹出的窗口需要用pywinauto选择图片
app = pywinauto.Desktop()
dlg = app["打开"]
dlg.print_control_identifiers()# 选中文件地址输入的工具框,# 因为不是输入框不能直接输入,需要通过键盘输入# 输入文件地址
dlg['Toolbar3'].click()
send_keys(file_path)# 输入图片名
dlg['Edit'].click()
dlg['Edit'].type_keys(f'"{file}"')for i in args:# 选择多个文件
send_keys(f'"{i}"')
dlg['打开(&O)'].click()
upload_img("图片{VK_RETURN}","壁纸.jpg","壁纸2.jpg")
17、项目实战之一 ——navicat新建连接
# 实现navicat的新建连接功能from pywinauto.application import Application
# app = Application('uia').start(r'E:\Navicat Premium 15\navicat.exe')# 为了不每次都重新打开navicat,运行一次打开新建连接页面后,使用句柄进行连接即可
app = Application('uia').connect(handle=526170)
dlg = app['Navicat Premium']# # 选择菜单栏
menu = dlg["Menu"]# menu.print_control_identifiers()# # 点击文件# 不可用 --> menu['文件'].click_input()file= menu.MenuItem1
file.click_input()# 与上面的方法一样# file = menu.child_window(title="文件", control_type="MenuItem")# file.click_input()# 报错 --- menu.child_window(title="新建连接", control_type="MenuItem").click_input()# # 点击新建连接
menu.item_by_path("文件->新建连接").click_input()# 只是使用这个不行,需要先点击文件,然后点击新建连接,然后点击mysql才行
menu.item_by_path("文件->新建连接->MySQL...").click_input()# =================================================# 填写连接数据# 选择新建连接窗口# dlg.print_control_identifiers()
dlg["Pane2"].print_control_identifiers()# 连接名
dlg["常规"].Edit5.type_keys("测试新建连接")# ip输入框# new_dlg["常规"]["Edit1"],报错,此时应该更换.的方式
dlg["常规"].Edit1.type_keys("127.0.0.1")# 端口输入框
dlg["常规"].Edit4.type_keys("3306")# 用户名输入框
dlg["常规"].Edit3.type_keys("root")# 密码输入框
dlg["常规"].Edit2.type_keys("123456")# 点击确定按钮,Button类型的就可以直接调用click()
dlg["确定"].click()
18、项目实战之二 —— 打开连接
# 重要:当控件不能点击的时候获取位置进行点击# 实现点击新建成的连接,# 因为该数据库是treeView不可点击的,所以要通过鼠标定位点击import pywinauto
from pywinauto import mouse
# 根据PID选择程序
app = pywinauto.Application(backend="uia").connect(handle=131914)# 根据窗口标题选择窗口
dlg = app["Navicat Premium"]# dlg.print_control_identifiers(depth=3)# 选择树状视图控件# [TVTFilterFrame][TPanel][TNavicatMainForm][#32769]# dlg["TTreeView"].print_control_identifiers()
dlg["TPanel"].print_control_identifiers()# 点击连接
db_name = dlg["TVirtualStringTree"].child_window(title="测试新建连接", control_type="TreeItem")# db_name.click() # 会报错,不可以点击# rectangle() 获取控件上下左右的位置;mid_point()获取中心点的位置
rect = db_name.rectangle().mid_point()print(rect.x, rect.y)
mouse.double_click(rect.x, rect.y)
19、项目实战之三 —— 删除连接
# 重要:点击后出现的窗口用viewwizard定位时消失的处理方法# 就是通过app.windows()获取当前应用程序的所有窗口定位# 实现点击删除连接,如何定位到该应用程序的其他窗口from pywinauto import Application
from pywinauto import mouse
# 根据PID选择程序
app = Application("uia").connect(process=4176)# 根据窗口标题选择窗口
dlg = app["Navicat Premium"]# 选择树状视图控件
dlg["TTreeView"].print_control_identifiers()# 点击连接
db_name = dlg["TTreeView"].child_window(title="测试新建连接", control_type="TreeItem")# db_name.click() # 会报错,不可以点击# rectangle() 获取控件上下左右的位置;mid_point()获取中心点的位置
rect = db_name.rectangle().mid_point()print(rect.x, rect.y)# 鼠标在控件中心点,右击
mouse.right_click(coords=(rect.x, rect.y))# 获取该应用程序的所有窗口print(app.windows())# 选择右击出现的上下文窗口# app["上下文"].print_control_identifiers()# 打开连接# app["上下文"]["MenuItem1"].click_input()# 删除连接
app["上下文"]["MenuItem5"].click_input()# 选择删除窗口
app["确认删除"]["删除"].click()
20、项目实战之代码封装一
# 将连接的动作封装起来from pywinauto.application import Application
from pywinauto import mouse
classNavicatTest:def__init__(self, path=None, precess=None):if path:
self.app = Application('uia').start(path)else:# 为了不每次都重新打开navicat,运行一次打开新建连接页面后,使用句柄进行连接即可
self.app = Application('uia').connect(handle=12)
self.dlg = self.app['Navicat Premium']defnew_connect(self):
menu = self.dlg["Menu"]# 点击文件
menu.child_window(title="文件").click_input()# 点击新建连接
menu.item_by_path("文件->新建连接").click_input()# 选择新建连接窗口
new_dlg = self.app["新建连接"]# 连接名
new_dlg["常规"].Edit5.type_keys("1111")# ip输入框# new_dlg["常规"]["Edit1"],报错,此时应该更换.的方式
new_dlg["常规"].Edit1.type_keys("1111")# 端口输入框
new_dlg["常规"].Edit4.type_keys("1111")# 用户名输入框
new_dlg["常规"].Edit3.type_keys("1111")# 密码输入框
new_dlg["常规"].Edit2.type_keys("1111")# 点击确定按钮,Button类型的就可以直接调用click()
new_dlg["确定"].click()defopen_connect(self):# 根据窗口标题选择窗口# self.dlg = self.app["Navicat Premium"]# 选择树状视图控件
self.dlg["TTreeView"].print_control_identifiers()# 点击连接
db_name = self.dlg["TTreeView"].child_window(title="测试新建连接", control_type="TreeItem")# db_name.click() # 会报错,不可以点击# rectangle() 获取控件上下左右的位置;mid_point()获取中心点的位置
rect = db_name.rectangle().mid_point()print(rect.x, rect.y)
mouse.double_click(rect.x, rect.y)defdel_connect(self):# 选择树状视图控件
self.dlg["TTreeView"].print_control_identifiers()# 点击连接
db_name = self.dlg["TTreeView"].child_window(title="测试新建连接", control_type="TreeItem")# rectangle() 获取控件上下左右的位置;mid_point()获取中心点的位置
rect = db_name.rectangle().mid_point()# 鼠标在控件中心点,右击
mouse.right_click(coords=(rect.x, rect.y))# 获取该应用程序的所有窗口# print(self.app.windows())# 删除连接
self.app["上下文"]["MenuItem5"].click_input()# 选择删除窗口
self.app["确认删除"]["删除"].click()
nav = NavicatTest(precess=12)
nav.new_connect()
21、项目实战之代码封装二
from pywinauto.application import Application
from pywinauto import mouse
classNavicatTest:def__init__(self, path=None, precess=None):if path:
self.app = Application('uia').start(path)else:# 为了不每次都重新打开navicat,运行一次打开新建连接页面后,使用句柄进行连接即可
self.app = Application('uia').connect(handle=12)
self.dlg = self.app['Navicat Premium']defnew_connect(self, title, host, port, user, password):'''新建连接'''
menu = self.dlg["Menu"]# 点击文件
menu.child_window(title="文件").click_input()# 点击新建连接
menu.item_by_path("文件->新建连接").click_input()# 选择新建连接窗口
new_dlg = self.app["新建连接"]# 连接名
new_dlg["常规"].Edit5.type_keys(title)# ip输入框# new_dlg["常规"]["Edit1"],报错,此时应该更换.的方式
new_dlg["常规"].Edit1.type_keys(host)# 端口输入框
new_dlg["常规"].Edit4.type_keys(port)# 用户名输入框
new_dlg["常规"].Edit3.type_keys(user)# 密码输入框
new_dlg["常规"].Edit2.type_keys(password)# 点击确定按钮,Button类型的就可以直接调用click()
new_dlg["确定"].click()defopen_connect(self, db_name):'''打开连接
打开连接和打开数据库的方法是一样的,
参数传数据库即可打开数据库,传连接名即可打开连接'''# 根据窗口标题选择窗口# self.dlg = self.app["Navicat Premium"]# 选择树状视图控件
self.dlg["TTreeView"].print_control_identifiers()# 点击连接
db_name = self.dlg["TTreeView"].child_window(title=db_name, control_type="TreeItem")# db_name.click() # 会报错,不可以点击# rectangle() 获取控件上下左右的位置;mid_point()获取中心点的位置
rect = db_name.rectangle().mid_point()print(rect.x, rect.y)
mouse.double_click(rect.x, rect.y)defdel_connect(self, title):'''删除连接'''# 选择树状视图控件
self.dlg["TTreeView"].print_control_identifiers()# 点击连接
db_name = self.dlg["TTreeView"].child_window(title=title, control_type="TreeItem")# rectangle() 获取控件上下左右的位置;mid_point()获取中心点的位置
rect = db_name.rectangle().mid_point()# 鼠标在控件中心点,右击
mouse.right_click(coords=(rect.x, rect.y))# 获取该应用程序的所有窗口# print(self.app.windows())# 删除连接
self.app["上下文"]["MenuItem5"].click_input()# 选择删除窗口
self.app["确认删除"]["删除"].click()defclose_connect(self, title):'''关闭连接
关闭连接和关闭数据库的方法是一样的,
参数传数据库即可关闭数据库,传连接名即可关闭连接'''# 选择树状视图控件
self.dlg["TTreeView"].print_control_identifiers()# 点击连接
db_name = self.dlg["TTreeView"].child_window(title=title, control_type="TreeItem")# rectangle() 获取控件上下左右的位置;mid_point()获取中心点的位置
rect = db_name.rectangle().mid_point()# 鼠标在控件中心点,右击
mouse.right_click(coords=(rect.x, rect.y))# 获取该应用程序的所有窗口# print(self.app.windows())# 关闭连接
self.app["上下文"]["MenuItem2"].click_input()defdel_database(self, title):'''删除数据库'''# 选择树状视图控件
self.dlg["TTreeView"].print_control_identifiers()# 点击连接
db_name = self.dlg["TTreeView"].child_window(title=title, control_type="TreeItem")# rectangle() 获取控件上下左右的位置;mid_point()获取中心点的位置
rect = db_name.rectangle().mid_point()# 鼠标在控件中心点,右击
mouse.right_click(coords=(rect.x, rect.y))# 获取该应用程序的所有窗口# print(self.app.windows())# 删除数据库
self.app["上下文"]["MenuItem4"].click_input()# 选择删除窗口
self.app["确认删除"]["删除"].click()
nav = NavicatTest(precess=12)
nav.new_connect('测试连接','127.0.0.1','3306','root','123456')
nav.open_connect('测试连接')
nav.del_connect("测试连接")
本文转载自: https://blog.csdn.net/weixin_43875895/article/details/124999040
版权归原作者 makabaka_222 所有, 如有侵权,请联系我们删除。
版权归原作者 makabaka_222 所有, 如有侵权,请联系我们删除。