本博客仅为个人学习使用,是看大佬视频做的笔记,侵权可联系作者删除~~
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)
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()
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()
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())
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)
# 点击菜单项用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()
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%')
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 = 0
def work():
global i
i += 1
print('当前i的值为:' , i)
return i
# 等待work返回的结果为5,继续往下执行
# wait_until(10, 1, work, 5)
# print('等待通过')
wait_until(10, 1, work, 15)
print('等待超时')
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()
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}')
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}")
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 in range(0, 1000, 50):
mouse.move(coords=(i, i))
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()
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()
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}")
# 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()
def upload_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")
# 实现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()
# 重要:当控件不能点击的时候获取位置进行点击
# 实现点击新建成的连接,
# 因为该数据库是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)
# 重要:点击后出现的窗口用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()
# 将连接的动作封装起来
from pywinauto.application import Application
from pywinauto import mouse
class NavicatTest:
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']
def new_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()
def open_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)
def del_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()
from pywinauto.application import Application
from pywinauto import mouse
class NavicatTest:
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']
def new_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()
def open_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)
def del_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()
def close_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()
def del_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("测试连接")