使用 PyWinAuto 控制 Windows 应用程序 (HMA VPN)
Control Windows app (HMA VPN) using PyWinAuto
我正在尝试编写 Python 代码来请求我的 vpn 软件在特定条件下连接/断开连接。我使用 HMA VPN 并且是 运行 Windows 10. Python 3.9.5.
PyWinAuto 模块似乎具有所需的功能,但我无法使其正常工作。我确定这是我的编码,而不是模块本身......;)
我相当确定当我使用 click() 方法调用它时我指的是错误的控件,但是任何人都可以建议正确的方法,因为我已经包含了 dump_tree 吗? (我已经根据 Getting Started guide 中的代码片段尝试了数十种变体,但并不愉快)。
我希望能够切换 GroupBox2 中的 Button4,它被命名为“Connect”或“Disconnect”,具体取决于 VPN 的当前状态。我还希望能够单击 Button5,“更改 IP 地址”,但是一旦我找出一个按钮,另一个按钮应该很容易。
有没有想过我哪里出错了?
我的代码片段如下:
from pywinauto import Desktop, Application
Desktop(backend='uia').HMAVPN.dump_tree()
app = Application().start('C:\Program Files\Privax\HMA VPN\Vpn.exe', timeout=5)
dlg_spec = app.window(title='HMA VPN')
dlg_spec.AvastChromiumWindow.Pane2.Document.GroupBox2.Button4.click()
结果输出如下:
Control Identifiers:
Dialog - 'HMA VPN' (L-149, T68, R551, B638)
['HMA VPNDialog', 'HMA VPN', 'Dialog']
child_window(title="HMA VPN", control_type="Window")
|
| Pane - 'AvastChromiumWindow' (L-149, T68, R551, B638)
| ['Pane', 'AvastChromiumWindowPane', 'AvastChromiumWindow', 'Pane0', 'Pane1']
| child_window(title="AvastChromiumWindow", control_type="Pane")
| |
| | Pane - '' (L-149, T68, R551, B638)
| | ['Pane2', '\ue01bPane', '\ue01bPane0', '\ue01bPane1']
| | |
| | | Document - ' Original IP 91.90.253.244 New IP 80.255.5.198 Original IP 91.90.253.244 Location Germany, Berlin ' (L-149, T68, R551, B638)
| | | ['\ue01b \ue014 \ue007 Original IP \xa0 91.90.253.244 New IP \xa0 80.255.5.198 \ue019 Original IP \xa0 91.90.253.244 \xa0 Location Germany, Berlin \ue005 Document', 'Document', '\ue01b \ue014 \ue007 Original IP \xa0 91.90.253.244 New IP \xa0 80.255.5.198 \ue019 Original IP \xa0 91.90.253.244 \xa0 Location Germany, Berlin \ue005 ']
| | | child_window(title=" Original IP 91.90.253.244 New IP 80.255.5.198 Original IP 91.90.253.244 Location Germany, Berlin ", auto_id="7211296", control_type="Document")
| | | |
| | | | GroupBox - '' (L-149, T68, R551, B104)
| | | | ['\ue01bGroupBox', 'GroupBox', '\ue01bGroupBox0', '\ue01bGroupBox1', 'GroupBox0', 'GroupBox1']
| | | | |
| | | | | Button - 'Preferences' (L-134, T76, R-114, B96)
| | | | | ['PreferencesButton', 'Preferences', 'Button', 'Button0', 'Button1']
| | | | | child_window(title="Preferences", auto_id="hma_title__preferences", control_type="Button")
| | | | | |
| | | | | | Static - '' (L-134, T76, R-114, B96)
| | | | | | ['Static', '\ue01b', '\ue01bStatic', 'Static0', 'Static1']
| | | | | | child_window(title="", control_type="Text")
| | | | |
| | | | | Button - 'Minimize' (L486, T76, R506, B96)
| | | | | ['Minimize', 'Button2', 'MinimizeButton']
| | | | | child_window(title="Minimize", control_type="Button")
| | | | | |
| | | | | | Static - '' (L486, T76, R506, B96)
| | | | | | ['\ue014Static', 'Static2', '\ue014']
| | | | | | child_window(title="", control_type="Text")
| | | | |
| | | | | Button - 'Close' (L516, T76, R536, B96)
| | | | | ['Close', 'Button3', 'CloseButton']
| | | | | child_window(title="Close", control_type="Button")
| | | | | |
| | | | | | Static - '' (L516, T76, R536, B96)
| | | | | | ['Static3', '\ue007', '\ue007Static']
| | | | | | child_window(title="", control_type="Text")
| | | |
| | | | GroupBox - '' (L-149, T68, R551, B638)
| | | | ['\ue01bGroupBox2', 'GroupBox2']
| | | | |
| | | | | Image - '' (L111, T120, R291, B300)
| | | | | ['\ue01bImage', 'Image']
| | | | |
| | | | | Button - 'Disconnect' (L126, T323, R276, B383)
| | | | | ['Button4', 'DisconnectButton', 'Disconnect']
| | | | | child_window(title="Disconnect", auto_id="dashboard_switch", control_type="Button")
| | | | |
| | | | | Static - 'Original IP' (L68, T414, R135, B430)
| | | | | ['Original IPStatic', 'Static4', 'Original IP', 'Original IPStatic0', 'Original IPStatic1', 'Original IP0', 'Original IP1']
| | | | | child_window(title="Original IP", control_type="Text")
| | | | |
| | | | | Static - ' ' (L164, T412, R168, B427)
| | | | | ['Static5', '\xa0Static', '\xa0', '\xa0Static0', '\xa0Static1', '\xa00', '\xa01']
| | | | | child_window(title=" ", control_type="Text")
| | | | |
| | | | | Static - '91.90.253.244' (L184, T414, R266, B429)
| | | | | ['Static6', '91.90.253.244Static', '91.90.253.244', '91.90.253.244Static0', '91.90.253.244Static1', '91.90.253.2440', '91.90.253.2441']
| | | | | child_window(title="91.90.253.244", control_type="Text")
| | | | |
| | | | | Static - 'New IP' (L68, T442, R113, B458)
| | | | | ['New IP', 'Static7', 'New IPStatic']
| | | | | child_window(title="New IP", control_type="Text")
| | | | |
| | | | | Static - ' ' (L164, T440, R168, B455)
| | | | | ['Static8', '\xa0Static2', '\xa02']
| | | | | child_window(title=" ", control_type="Text")
| | | | |
| | | | | Static - '80.255.5.198' (L184, T442, R258, B457)
| | | | | ['Static9', '80.255.5.198', '80.255.5.198Static']
| | | | | child_window(title="80.255.5.198", control_type="Text")
| | | | |
| | | | | Button - 'Change IP Address' (L294, T416, R334, B456)
| | | | | ['Change IP AddressButton', 'Button5', 'Change IP Address']
| | | | | child_window(title="Change IP Address", auto_id="ip_change", control_type="Button")
| | | | |
| | | | | Static - 'Original IP' (L95, T428, R162, B444)
| | | | | ['Original IPStatic2', 'Static10', 'Original IP2']
| | | | | child_window(title="Original IP", control_type="Text")
| | | | |
| | | | | Static - ' ' (L191, T426, R196, B441)
| | | | | ['Static11', '\xa0Static3', '\xa03']
| | | | | child_window(title=" ", control_type="Text")
| | | | |
| | | | | Static - '91.90.253.244' (L211, T428, R293, B443)
| | | | | ['Static12', '91.90.253.244Static2', '91.90.253.2442']
| | | | | child_window(title="91.90.253.244", control_type="Text")
| | | | |
| | | | | Button - 'Location Germany, Berlin' (L31, T489, R371, B569)
| | | | | ['Button6', 'Location Germany, BerlinButton', 'Location Germany, Berlin']
| | | | | child_window(title="Location Germany, Berlin", auto_id="dashboard_chooseLocation", control_type="Button")
| | | | | |
| | | | | | Static - ' ' (L51, T507, R55, B522)
| | | | | | ['Static13', '\xa0Static4', '\xa04']
| | | | | | child_window(title=" ", control_type="Text")
| | | | | |
| | | | | | Static - 'Location' (L111, T511, R164, B526)
| | | | | | ['Static14', 'Location', 'LocationStatic']
| | | | | | child_window(title="Location", control_type="Text")
| | | | | |
| | | | | | Static - 'Germany, Berlin' (L111, T529, R219, B546)
| | | | | | ['Static15', 'Germany, Berlin', 'Germany, BerlinStatic']
| | | | | | child_window(title="Germany, Berlin", control_type="Text")
| | | | | |
| | | | | | Static - '' (L331, T519, R351, B539)
| | | | | | ['Static16', '\ue005', '\ue005Static']
| | | | | | child_window(title="", control_type="Text")
| | | | |
| | | | | Button - 'More' (L420, T107, R528, B137)
| | | | | ['More', 'Button7', 'MoreButton']
| | | | | child_window(title="More", control_type="Button")
| | |
| | | Pane - '' (L-149, T68, R551, B638)
| | | ['Pane3', '\ue01bPane2']
Traceback (most recent call last):
File "C:\Users\db533\VirtualBox VMs\pycharm-gunabot\venv\lib\site-packages\pywinauto\application.py", line 250, in __resolve_control
ctrl = wait_until_passes(
File "C:\Users\db533\VirtualBox VMs\pycharm-gunabot\venv\lib\site-packages\pywinauto\timings.py", line 458, in wait_until_passes
raise err
pywinauto.timings.TimeoutError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\db533\PycharmProjects\GunaBot\hma_control.py", line 19, in <module>
dlg_spec.AvastChromiumWindow.Pane2.Document.GroupBox2.Button4.click()
File "C:\Users\db533\VirtualBox VMs\pycharm-gunabot\venv\lib\site-packages\pywinauto\application.py", line 379, in __getattribute__
ctrls = self.__resolve_control(self.criteria)
File "C:\Users\db533\VirtualBox VMs\pycharm-gunabot\venv\lib\site-packages\pywinauto\application.py", line 261, in __resolve_control
raise e.original_exception
File "C:\Users\db533\VirtualBox VMs\pycharm-gunabot\venv\lib\site-packages\pywinauto\timings.py", line 436, in wait_until_passes
func_val = func(*args, **kwargs)
File "C:\Users\db533\VirtualBox VMs\pycharm-gunabot\venv\lib\site-packages\pywinauto\application.py", line 203, in __get_ctrl
dialog = self.backend.generic_wrapper_class(findwindows.find_element(**criteria[0]))
File "C:\Users\db533\VirtualBox VMs\pycharm-gunabot\venv\lib\site-packages\pywinauto\findwindows.py", line 87, in find_element
raise ElementNotFoundError(kwargs)
pywinauto.findwindows.ElementNotFoundError: {'title': 'HMA VPN', 'backend': 'win32', 'process': 40580}
Process finished with exit code 1
破解了!下面的代码让我切换连接/断开连接按钮并更改 IP。
from pywinauto import Desktop,Application
vpn_app = Application(backend="uia").start('C:\Program Files\Privax\HMA VPN\Vpn.exe')
dialog=Desktop(backend="uia").HMA
panel0=dialog.Pane
# Command to connect / disconnect the VPN: connect_button.click()
connect_button=panel0.ConnectButton
# Command to change the IP address: changeIP.click()
changeIP=panel0.Button5
# Check VPN state:
# 0 if disconnected
# 1 if connected
print(connect_button.get_toggle_state())
# Command to connect / disconnect the VPN: connect_button.click()
connect_button=panel0.ConnectButton
connect_button.click()
# Command to change the IP address: changeIP.click()
changeIP=panel0.Button5
changeIP.click()
# Check VPN state:
# 0 if disconnected
# 1 if connected
print(connect_button.get_toggle_state())
我正在尝试编写 Python 代码来请求我的 vpn 软件在特定条件下连接/断开连接。我使用 HMA VPN 并且是 运行 Windows 10. Python 3.9.5.
PyWinAuto 模块似乎具有所需的功能,但我无法使其正常工作。我确定这是我的编码,而不是模块本身......;)
我相当确定当我使用 click() 方法调用它时我指的是错误的控件,但是任何人都可以建议正确的方法,因为我已经包含了 dump_tree 吗? (我已经根据 Getting Started guide 中的代码片段尝试了数十种变体,但并不愉快)。
我希望能够切换 GroupBox2 中的 Button4,它被命名为“Connect”或“Disconnect”,具体取决于 VPN 的当前状态。我还希望能够单击 Button5,“更改 IP 地址”,但是一旦我找出一个按钮,另一个按钮应该很容易。
有没有想过我哪里出错了?
我的代码片段如下:
from pywinauto import Desktop, Application
Desktop(backend='uia').HMAVPN.dump_tree()
app = Application().start('C:\Program Files\Privax\HMA VPN\Vpn.exe', timeout=5)
dlg_spec = app.window(title='HMA VPN')
dlg_spec.AvastChromiumWindow.Pane2.Document.GroupBox2.Button4.click()
结果输出如下:
Control Identifiers:
Dialog - 'HMA VPN' (L-149, T68, R551, B638)
['HMA VPNDialog', 'HMA VPN', 'Dialog']
child_window(title="HMA VPN", control_type="Window")
|
| Pane - 'AvastChromiumWindow' (L-149, T68, R551, B638)
| ['Pane', 'AvastChromiumWindowPane', 'AvastChromiumWindow', 'Pane0', 'Pane1']
| child_window(title="AvastChromiumWindow", control_type="Pane")
| |
| | Pane - '' (L-149, T68, R551, B638)
| | ['Pane2', '\ue01bPane', '\ue01bPane0', '\ue01bPane1']
| | |
| | | Document - ' Original IP 91.90.253.244 New IP 80.255.5.198 Original IP 91.90.253.244 Location Germany, Berlin ' (L-149, T68, R551, B638)
| | | ['\ue01b \ue014 \ue007 Original IP \xa0 91.90.253.244 New IP \xa0 80.255.5.198 \ue019 Original IP \xa0 91.90.253.244 \xa0 Location Germany, Berlin \ue005 Document', 'Document', '\ue01b \ue014 \ue007 Original IP \xa0 91.90.253.244 New IP \xa0 80.255.5.198 \ue019 Original IP \xa0 91.90.253.244 \xa0 Location Germany, Berlin \ue005 ']
| | | child_window(title=" Original IP 91.90.253.244 New IP 80.255.5.198 Original IP 91.90.253.244 Location Germany, Berlin ", auto_id="7211296", control_type="Document")
| | | |
| | | | GroupBox - '' (L-149, T68, R551, B104)
| | | | ['\ue01bGroupBox', 'GroupBox', '\ue01bGroupBox0', '\ue01bGroupBox1', 'GroupBox0', 'GroupBox1']
| | | | |
| | | | | Button - 'Preferences' (L-134, T76, R-114, B96)
| | | | | ['PreferencesButton', 'Preferences', 'Button', 'Button0', 'Button1']
| | | | | child_window(title="Preferences", auto_id="hma_title__preferences", control_type="Button")
| | | | | |
| | | | | | Static - '' (L-134, T76, R-114, B96)
| | | | | | ['Static', '\ue01b', '\ue01bStatic', 'Static0', 'Static1']
| | | | | | child_window(title="", control_type="Text")
| | | | |
| | | | | Button - 'Minimize' (L486, T76, R506, B96)
| | | | | ['Minimize', 'Button2', 'MinimizeButton']
| | | | | child_window(title="Minimize", control_type="Button")
| | | | | |
| | | | | | Static - '' (L486, T76, R506, B96)
| | | | | | ['\ue014Static', 'Static2', '\ue014']
| | | | | | child_window(title="", control_type="Text")
| | | | |
| | | | | Button - 'Close' (L516, T76, R536, B96)
| | | | | ['Close', 'Button3', 'CloseButton']
| | | | | child_window(title="Close", control_type="Button")
| | | | | |
| | | | | | Static - '' (L516, T76, R536, B96)
| | | | | | ['Static3', '\ue007', '\ue007Static']
| | | | | | child_window(title="", control_type="Text")
| | | |
| | | | GroupBox - '' (L-149, T68, R551, B638)
| | | | ['\ue01bGroupBox2', 'GroupBox2']
| | | | |
| | | | | Image - '' (L111, T120, R291, B300)
| | | | | ['\ue01bImage', 'Image']
| | | | |
| | | | | Button - 'Disconnect' (L126, T323, R276, B383)
| | | | | ['Button4', 'DisconnectButton', 'Disconnect']
| | | | | child_window(title="Disconnect", auto_id="dashboard_switch", control_type="Button")
| | | | |
| | | | | Static - 'Original IP' (L68, T414, R135, B430)
| | | | | ['Original IPStatic', 'Static4', 'Original IP', 'Original IPStatic0', 'Original IPStatic1', 'Original IP0', 'Original IP1']
| | | | | child_window(title="Original IP", control_type="Text")
| | | | |
| | | | | Static - ' ' (L164, T412, R168, B427)
| | | | | ['Static5', '\xa0Static', '\xa0', '\xa0Static0', '\xa0Static1', '\xa00', '\xa01']
| | | | | child_window(title=" ", control_type="Text")
| | | | |
| | | | | Static - '91.90.253.244' (L184, T414, R266, B429)
| | | | | ['Static6', '91.90.253.244Static', '91.90.253.244', '91.90.253.244Static0', '91.90.253.244Static1', '91.90.253.2440', '91.90.253.2441']
| | | | | child_window(title="91.90.253.244", control_type="Text")
| | | | |
| | | | | Static - 'New IP' (L68, T442, R113, B458)
| | | | | ['New IP', 'Static7', 'New IPStatic']
| | | | | child_window(title="New IP", control_type="Text")
| | | | |
| | | | | Static - ' ' (L164, T440, R168, B455)
| | | | | ['Static8', '\xa0Static2', '\xa02']
| | | | | child_window(title=" ", control_type="Text")
| | | | |
| | | | | Static - '80.255.5.198' (L184, T442, R258, B457)
| | | | | ['Static9', '80.255.5.198', '80.255.5.198Static']
| | | | | child_window(title="80.255.5.198", control_type="Text")
| | | | |
| | | | | Button - 'Change IP Address' (L294, T416, R334, B456)
| | | | | ['Change IP AddressButton', 'Button5', 'Change IP Address']
| | | | | child_window(title="Change IP Address", auto_id="ip_change", control_type="Button")
| | | | |
| | | | | Static - 'Original IP' (L95, T428, R162, B444)
| | | | | ['Original IPStatic2', 'Static10', 'Original IP2']
| | | | | child_window(title="Original IP", control_type="Text")
| | | | |
| | | | | Static - ' ' (L191, T426, R196, B441)
| | | | | ['Static11', '\xa0Static3', '\xa03']
| | | | | child_window(title=" ", control_type="Text")
| | | | |
| | | | | Static - '91.90.253.244' (L211, T428, R293, B443)
| | | | | ['Static12', '91.90.253.244Static2', '91.90.253.2442']
| | | | | child_window(title="91.90.253.244", control_type="Text")
| | | | |
| | | | | Button - 'Location Germany, Berlin' (L31, T489, R371, B569)
| | | | | ['Button6', 'Location Germany, BerlinButton', 'Location Germany, Berlin']
| | | | | child_window(title="Location Germany, Berlin", auto_id="dashboard_chooseLocation", control_type="Button")
| | | | | |
| | | | | | Static - ' ' (L51, T507, R55, B522)
| | | | | | ['Static13', '\xa0Static4', '\xa04']
| | | | | | child_window(title=" ", control_type="Text")
| | | | | |
| | | | | | Static - 'Location' (L111, T511, R164, B526)
| | | | | | ['Static14', 'Location', 'LocationStatic']
| | | | | | child_window(title="Location", control_type="Text")
| | | | | |
| | | | | | Static - 'Germany, Berlin' (L111, T529, R219, B546)
| | | | | | ['Static15', 'Germany, Berlin', 'Germany, BerlinStatic']
| | | | | | child_window(title="Germany, Berlin", control_type="Text")
| | | | | |
| | | | | | Static - '' (L331, T519, R351, B539)
| | | | | | ['Static16', '\ue005', '\ue005Static']
| | | | | | child_window(title="", control_type="Text")
| | | | |
| | | | | Button - 'More' (L420, T107, R528, B137)
| | | | | ['More', 'Button7', 'MoreButton']
| | | | | child_window(title="More", control_type="Button")
| | |
| | | Pane - '' (L-149, T68, R551, B638)
| | | ['Pane3', '\ue01bPane2']
Traceback (most recent call last):
File "C:\Users\db533\VirtualBox VMs\pycharm-gunabot\venv\lib\site-packages\pywinauto\application.py", line 250, in __resolve_control
ctrl = wait_until_passes(
File "C:\Users\db533\VirtualBox VMs\pycharm-gunabot\venv\lib\site-packages\pywinauto\timings.py", line 458, in wait_until_passes
raise err
pywinauto.timings.TimeoutError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\db533\PycharmProjects\GunaBot\hma_control.py", line 19, in <module>
dlg_spec.AvastChromiumWindow.Pane2.Document.GroupBox2.Button4.click()
File "C:\Users\db533\VirtualBox VMs\pycharm-gunabot\venv\lib\site-packages\pywinauto\application.py", line 379, in __getattribute__
ctrls = self.__resolve_control(self.criteria)
File "C:\Users\db533\VirtualBox VMs\pycharm-gunabot\venv\lib\site-packages\pywinauto\application.py", line 261, in __resolve_control
raise e.original_exception
File "C:\Users\db533\VirtualBox VMs\pycharm-gunabot\venv\lib\site-packages\pywinauto\timings.py", line 436, in wait_until_passes
func_val = func(*args, **kwargs)
File "C:\Users\db533\VirtualBox VMs\pycharm-gunabot\venv\lib\site-packages\pywinauto\application.py", line 203, in __get_ctrl
dialog = self.backend.generic_wrapper_class(findwindows.find_element(**criteria[0]))
File "C:\Users\db533\VirtualBox VMs\pycharm-gunabot\venv\lib\site-packages\pywinauto\findwindows.py", line 87, in find_element
raise ElementNotFoundError(kwargs)
pywinauto.findwindows.ElementNotFoundError: {'title': 'HMA VPN', 'backend': 'win32', 'process': 40580}
Process finished with exit code 1
破解了!下面的代码让我切换连接/断开连接按钮并更改 IP。
from pywinauto import Desktop,Application
vpn_app = Application(backend="uia").start('C:\Program Files\Privax\HMA VPN\Vpn.exe')
dialog=Desktop(backend="uia").HMA
panel0=dialog.Pane
# Command to connect / disconnect the VPN: connect_button.click()
connect_button=panel0.ConnectButton
# Command to change the IP address: changeIP.click()
changeIP=panel0.Button5
# Check VPN state:
# 0 if disconnected
# 1 if connected
print(connect_button.get_toggle_state())
# Command to connect / disconnect the VPN: connect_button.click()
connect_button=panel0.ConnectButton
connect_button.click()
# Command to change the IP address: changeIP.click()
changeIP=panel0.Button5
changeIP.click()
# Check VPN state:
# 0 if disconnected
# 1 if connected
print(connect_button.get_toggle_state())