赞
踩
想在Windows系统里实现一些程序的点击操作
如果用类似按键精灵的包是pyautogui,也可以针对一个图片进行点击,但都不是很精准;
通过pywinauto可以智能找到相关程序、按钮和菜单,实现启动、关闭、点击,输入文字等功能。
特点:通过进程、菜单、按钮等直接控制
安装的时候,遇到了一些插件需要再装
ModuleNotFoundError: No module named ‘win32api’
提示错误,需要安装pypiwin32这个插件:
pip install pypiwin32
又提示错误
ModuleNotFoundError: No module named ‘six’
装完提示,需要comtypes
完成安装
程序的backend有如下两种:
还有一种py_inspect支持以上两种类型
只有当以上工具都探测不到的时候,再考虑用鼠标和键盘
from pywinauto.application import Application
app = Application(backend="uia").start('notepad.exe')
# describe the window inside Notepad.exe process
dlg_spec = app.UntitledNotepad
# wait till the window is really open
actionable_dlg = dlg_spec.wait('visible')
from subprocess import Popen
from pywinauto import Desktop
Popen('calc.exe', shell=True)
dlg = Desktop(backend="uia").Calculator
dlg.wait('visible')
最终都是timeout,可能我的电脑没有计算器
这两个都是特定的程序类型,后面不用使用具体程序名称。
>>> dlg_spec = app.window(title='Untitled - Notepad')
>>> dlg_spec
<pywinauto.application.WindowSpecification object at 0x0568B790>
>>> dlg_spec.wrapper_object()
<pywinauto.controls.win32_controls.DialogWrapper object at 0x05639B70>
窗口规则是给后续高级操作用的,有更细节的操作,或在程序还没开启时用
其中wrapper是包装器,我运行报错
另外以下两个语言是一样的效果,相当于是简化了语言
dlg_spec.wrapper_object().minimize() # while debugging
dlg_spec.minimize() # in production
# can be multi-level
app.window(title_re='.* - Notepad$').window(class_name='Edit')
# can combine criteria 组合条件
dlg = Desktop(backend="uia").Calculator
dlg.window(auto_id='num8Button', control_type='Button')
空格、逗号、大小写,都可以通过最佳匹配来查找
app.UntitledNotepad
# is equivalent to
app.window(best_match='UntitledNotepad')
一些unicode和特色字符,可以像字典一样
app['Untitled - Notepad']
# is the same as
app.window(best_match='Untitled - Notepad')
app.Properties.OK.click()
app.Properties.OKButton.click()
app.Properties.Button3.click()
(Button0和Button1是同一个按钮,Button2才是下一个)
app.OpenDialog.FileNameEdit.set_text("")
不是所有同时可用,针对特定的对话框,可使用以下命令检查名称,通过最佳匹配名称,列出所有的子项:
app.UntitledNotepad.print_control_identifiers()
Control Identifiers:
Notepad - '无标题 - 记事本' (L251, T293, R642, B681)
['无标题 - 记事本Notepad', 'Notepad', '无标题 - 记事本']
child_window(title="无标题 - 记事本", class_name="Notepad")
|
| Edit - '' (L259, T344, R634, B651)
| ['Edit', '无标题 - 记事本Edit']
| child_window(class_name="Edit")
|
| StatusBar - '' (L259, T651, R634, B673)
| ['StatusBar 100%', 'StatusBar', 'StatusBar UTF-8', 'StatusBar Windows (CRLF)', '无标题 - 记事本StatusBar', 'StatusBar 第 1 行,第 1 列']
| child_window(class_name="msctls_statusbar32")
如果还要进一步看细节,可以用以下命令(未测试):
app.Properties.child_window(title="Contains:", auto_id="13087", control_type="Edit")
from pywinauto import application
app = application.Application()
app.start("Notepad.exe")
<pywinauto.application.Application object at 0x0000017B785502B0>
app.UntitledNotepad.draw_outline()
注意这里app就是应用,并不能直接赋值为start,否则后面的属性就不太好调用了
app.UntitledNotepad.menu_select("Edit -> Replace")
app.UntitledNotepad.menu_select("编辑(&E) -> 替换(&R)")
相当于按了它的菜单-编辑-替换按钮
app.替换.print_control_identifiers() Control Identifiers: Dialog - '替换' (L322, T438, R741, B677) ['替换', 'Dialog', '替换Dialog'] child_window(title="替换", class_name="#32770") | | Static - '查找内容(&N):' (L337, T488, R421, B505) | ['Static', '查找内容(&N):', '查找内容(&N):Static', 'Static0', 'Static1'] | child_window(title="查找内容(&N):", class_name="Static") | | Edit - '张' (L425, T484, R625, B510) | ['Edit', '查找内容(&N):Edit', 'Edit0', 'Edit1'] | child_window(title="张", class_name="Edit") | | Static - '替换为(&P):' (L337, T524, R421, B541) | ['Static2', '替换为(&P):', '替换为(&P):Static'] | child_window(title="替换为(&P):", class_name="Static") | | Edit - '' (L425, T520, R625, B546) | ['Edit2', '替换为(&P):Edit'] | child_window(class_name="Edit") | | CheckBox - '全字匹配(&W)' (L337, T567, R519, B593) | ['CheckBox', '全字匹配(&W)CheckBox', '全字匹配(&W)', 'CheckBox0', 'CheckBox1'] | child_window(title="全字匹配(&W)", class_name="Button") | | CheckBox - '区分大小写(&C)' (L337, T601, R440, B627) | ['区分大小写(&C)', 'CheckBox2', '区分大小写(&C)CheckBox'] | child_window(title="区分大小写(&C)", class_name="Button") | | CheckBox - '循环(&R)' (L337, T635, R449, B661) | ['循环(&R)CheckBox', '循环(&R)', 'CheckBox3'] | child_window(title="循环(&R)", class_name="Button") | | Button - '查找下一个(&F)' (L635, T478, R723, B508) | ['查找下一个(&F)', '查找下一个(&F)Button', 'Button', 'Button0', 'Button1'] | child_window(title="查找下一个(&F)", class_name="Button") | | Button - '替换(&R)' (L635, T514, R723, B544) | ['替换(&R)Button', '替换(&R)', 'Button2'] | child_window(title="替换(&R)", class_name="Button") | | Button - '全部替换(&A)' (L635, T550, R723, B580) | ['全部替换(&A)', '全部替换(&A)Button', 'Button3'] | child_window(title="全部替换(&A)", class_name="Button") | | Button - '取消' (L635, T586, R723, B616) | ['Button4', '取消Button', '取消'] | child_window(title="取消", class_name="Button") | | Button - '帮助(&H)' (L635, T628, R723, B658) | ['帮助(&H)', '帮助(&H)Button', 'Button5'] | child_window(title="帮助(&H)", class_name="Button") | | Static - '' (L337, T631, R339, B633) | ['Static3', '区分大小写(&C)Static'] | child_window(class_name="Static")
对显示的控件信息,可以用以下方式去选择,例如查找内容的输入框。
最后一个是中文版的
app.Replace.Edit
app.Replace.Edit0
app.Replace.Edit1
app.FindwhatEdit
app.查找内容Edit
关闭弹窗
方法1,点击取消键
app.Replace.Cancel.click()
方法2,按关闭按钮,比较稳妥,因为稍微耗时多一点
close_click()
输入文字
app.UntitledNotepad.Edit.type_keys(“Hi from Python interactive prompt %s” % str(dir()), with_spaces = True)
无标题记事本,英文UntitledNotepad可以用,中文也可以,效果一样
输入%s占位符,后面字符串是dos命令文件夹列表dir
可以选择空格是否需要,true、0/1都可以表示
选择菜单:文件-退出;点击:不保存
app.UntitledNotepad.menu_select(“文件 -> 退出”)
app.记事本.不保存.click()
dialog对话框包括window主窗口和顶部的消息框
control控件是GUI图形化界面的任一级别的元素
Win32的API为每个控件提供了标识符,handle整数
UI自动化API,handle句柄可能是隐藏的,需要用inspect.exe来查找
start(self, cmd_line, timeout=app_start_timeout) # instance method:
app = Application().start(r"c:\path\to\your\application -a -n -y --arguments")
包含等待启动的时间,为可选项
(2)连接应用
连接方式有进程号、句柄号(每次启动随机)、路径、标题和类名,其中.*是部分内容模糊查询
connect(self, **kwargs) # instance method:
app = Application().connect(process=2341)
app = Application().connect(handle=0x010f0c)
app = Application().connect(path=r"c:\windows\system32\notepad.exe")
app = Application().connect(title_re=".*Notepad", class_name="Notepad")
如果应用不在这个程序里启动,需要进行连接,这里没有指定等待时间,需要单独写该命令
前两个一样,第三个是置顶窗口,第四个可以指定具体的名称
dlg = app.Notepad
dlg = app['Notepad']
dlg = app.top_window()
dlg = app.window(title_re="Page Setup", class_name="#32770")
查看所有窗口,或指定句柄、过长的名称可用.*模糊查询
dialogs = app.windows()
app.window(handle=win)
app.window(title_re=".*Part of Title.*")
第二种适合中文名称
app.dlg.control
app['dlg']['control']
app.YourDialog.print_control_identifiers()
也可以点击右下角系统托盘(通知区域)按钮
利用pyinstaller
需要安装pywin32-ctypes、altgraph、 pefile>=2017.8.1、 pyinstaller-hooks-contrib>=2020.6,
安装命令是pip install pywin32-ctypes(据说10月后pip会变化)
将刚才做的.py文件,放在同文件夹里,运行下面的语言,生成exe文件
python pyinstaller.py -F auto1.py
pywinauto官网列举了一些可以直接启动的工具,还没有测试
其他地方有socket感觉也不太好
目前想到的是利用自带的winrm程序,执行cmd命令,运行刚才的app,可能会遇到桌面是否在用的情况。
需要安装pywimrm
安装过程出现了一点问题,补了一个插件后才装好,pip install chardet
pip install pywinrm2-0.0.0-py2.py3-none-any.whl
安装这种whl文件,需要cd到目录,且不能改变文件名
如果在没有pycharm的电脑里装,会提示缺少xmltodic、requests、urllib等
import winrm
# r = s.run_cmd('cd /d d: & dir')
# 链接服务器
s = winrm.Session('http://xx.xx.xx.xx:5985/wsman', auth=('username', 'password'))
# 查看备份是否OK
def shg_erp():
r = s.run_cmd('if exist "D:\ERPbeifen\BSERP3_backup_'
'%date:~0,4%_%date:~5,2%_%date:~8,2%*.bak"'
' (echo 1) else (echo 0)')
————————————————————————————————————————————————————————————————————————————————
以下是春节写的比较老了,暂时不用看
特点:图片识别,鼠标和键盘按钮
工作中有很多重复的操作,有些可以固化成程序来完成:
有个软件因为没有激活,会定期(5分钟左右)触发关闭按钮,导致程序无法使用。如果靠人工一直去点击也是不现实的。
之前看过王者荣耀模拟器点击金币教学,固定位置的做法,虽然简单,但需要保证这个点位置在某个时间是确定的。暂时不考虑。
如果用原生语言,就连左右键、键盘输入转换码,这些基本功能都非常复杂,后来发现已融合到这个pyautogui库里:
pip install pyautogui
自动安装这个坑很多,还是去PyPI里下载好安装,有多个文件格式,安装在英文目录里,cmd运行即可;安的时候提示缺文件,还是再下载装了。
想要点击的东西,例如chrome图标,将其截图,保存在py文件目录。一定要用小写的png,今天被这个代码原文章坑了,它居然用大写
pyautogui的常用函数:
import pyautogui
x = pyautogui.locateCenterOnScreen('chrome.png', confidence=0.9)
print(x)
pyautogui.doubleClick(x)
输出结果
Point(x=262, y=465)
for pos in pyautogui.locateAllOnScreen('chrome.png', confidence=0.95):
print(pos)
x, y = pyautogui.center(pos)
print('center()', x, y)
pyautogui.click(x=x,y=y,clicks=1,button='left')
输出结果
Point(x=262, y=465)
Box(left=237, top=438, width=50, height=54)
center() 262 465
Box(left=237, top=439, width=50, height=54)
center() 262 466
Box(left=237, top=440, width=50, height=54)
center() 262 467
小例子:实现自动按计算器
x = [0]*4
x[0] = pyautogui.locateCenterOnScreen('3.png')
x[1] = pyautogui.locateCenterOnScreen('+.png')
x[2] = pyautogui.locateCenterOnScreen('4.png')
x[3] = pyautogui.locateCenterOnScreen('=.png')
print(x)
for i in range(4):
pyautogui.click(x[i])
要将计算器的各个按钮截图保存下,重点看下数组的使用;
pyautogui截图对比,除了上面的OnScreen与屏幕比,还可以跟自定义图片比,由于用不到,这里就不展开了。
在上面打开chrome程序后,可以实现其他实现的功能:延时、快捷键ctrl和t新建页面,ctrl+l定位在地址栏,输入网址,按下两次回车键,截屏保存在程序文件夹
pyautogui.PAUSE = 2
pyautogui.hotkey('ctrl', 't')
pyautogui.hotkey('ctrl', 'l')
pyautogui.typewrite("www.dangdang.com")
pyautogui.keyDown('enter')
pyautogui.keyDown('enter')
pyautogui.PAUSE = 2
im2 = pyautogui.screenshot('my_screenshot.png')
前面的问题是,如果程序在后台怎么切到前台,程序被挡了,图片对比无法正常使用…
有人推荐pywinauto,但是写的时候发现并没有这个函数…
from pywinauto.win32functions import SetForegroundWindow
这个暂时不研究了…
如果操作电脑的步骤可以很明确的写出来,而且前提是这个程序就在桌面能看到的地方在运行,那之前的pyautogui还是很方便的,类似按键精灵吧。
我想到的例子是之前登陆网页版IP摄像机进行自动对焦,如果写出来什么时候干什么事,然后再进行循环,的确可以批量完成。但是这个最好还是可以通过调用硬件接口直接去进行控制,以后研究下。
当然如果还是想通过点击来实现,上次的图片对比面临两个问题:
我测的类型都是UIA,即ControlType: UIA_WindowControlTypeId,原版教程有个测不出来类型的是win32型。
通常的单进程用Application(),罕见的跨进程Desktop()暂不考虑,比如计算器
其实这个原生的os就可以实现~u是unique的意思
import os
os.system(u"C:\\Windows\\System32\\notepad.exe")
os其他功能就不深究了,试了试都出不来,感觉是Windows不支持
pywinauto的实现方式
from pywinauto import Application
app = Application().start(r"C:\Program Files (x86)\Thunder Network\Thunder\Program\Thunder.exe")
成功打开迅雷
from pywinauto import Application
app = Application().connect(process=10276)
弊端是进程号每次重启都不固定
WIN7还是用inspect看,WIN10在任务管理器里有
app = Application().connect(handle=0x00250512)
模板里中间多了两个0,先按这样补00
弊端同上不稳定,查看只能用inspect
app = Application().connect(path=r"C:\Program Files (x86)\Thunder Network\Thunder\Program\Thunder.exe")
跟第一个打开程序很像
app = Application().connect(title_re="截屏程序.*", class_name="TMainForm")
inspect上面都有,但是不是每个控件都有这些信息,要看具体看情况~
我们以截屏程序为例,在程序连接后(app),通过window选择窗体
便可按菜单进行操作,或通过快捷键进行操作
prt_sc = app.window(title='截屏程序’)
prt_sc.menu_select(r"文件->另存为")
或
prt_sc.type_keys('%TPR')
其中%代表ALT,一般像文字带括号,都是用ALT触发,例如:工具(T)笔(P)红笔(R);还可以用^代表快捷键CTRL,另存为是CTRL+S
看上去很复杂
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。