pywinauto find_elements() returns ElementNotFoundError
pywinauto find_elements() returns ElementNotFoundError
我正在尝试使用 pywinauto 和 Python 3.6 自动化一个简单的应用程序。该应用程序有一个 Windows "Open" 对话框,我想单击 "Cancel" 按钮:
我使用 SWAPY 获取按钮的 class_name 和 control_id 属性。
现在的问题是,当我使用这些参数调用 find_element() 方法时,它会引发 ElementNotFoundError。这是我的代码:
cancel_button = pywinauto.findwindows.find_element(class_name="button", control_id=2)
我试过(class_name="button", control_id="2")
、(class_name="Button", control_id=2)
,但它们都给出相同的错误。我试图在此对话框中找到的任何其他元素都会出现同样的问题。
那么如何使用从 SWAPY 读取的属性呢?我没有发现官方的 pywinauto 文档非常有用。很多东西都没有解释清楚。
编辑: 我决定不使用 find_elements 方法,而是使用 find_windows() 来获取“打开”对话框的句柄。
w_open_handle = pywinauto.findwindows.find_windows(title=u'Open', class_name='#32770')[0]
然后我使用这个句柄得到一个 WindowSpecification 对象:
w_open = app.window_(handle=w_open_handle)
然后我打电话给:
w_open['Cancel'].click()
这行得通。现在我想在 "File name:" 编辑框中输入一个文件名,然后单击打开按钮打开该文件。所以我这样做:
w_open['File name:'].type_keys("abc.txt")
这行得通。我使用 print_control_identifiers() 打印出控件标识符,并获得了“打开”按钮的名称。所以使用 draw_outline() 我在它外面画了一个边界,它显示了正确的按钮。
w_open['SplitButton6'].draw_outline()
但是在 'SplitButton6' 上调用 .click() 方法会引发 WindowSpecification class 没有 'click' 方法 错误。知道是什么原因造成的吗?该错误似乎具有误导性,因为 WindowSpec class 确实有一个 .click 方法。
正确答案是您错过了 top_level_only=False
(默认情况下是 True
,因为更高级别 API 至少调用它两次)。那么您可能有 2 个控件符合此条件(可能来自不同的应用程序)。 find_element
是低级函数。不推荐直接使用(代码太长,有很多坑,上级考虑到了API)。
>>> pywinauto.findwindows.find_element(class_name="Button", control_id=2, top_level_only=False)
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
File "...\pywinauto\findwindows.py", line 98, in find_element
raise exception
ElementAmbiguousError: There are 2 elements that match the criteria {'class_name': 'Button', 'control_id': 2, 'top_level_only': False}
>>> pywinauto.findwindows.find_element(class_name="Button", title='Cancel', top_level_only=False)
<win32_element_info.HwndElementInfo - 'Cancel', Button, 395554>
使用更高级别 API(Application
对象和 WindowSpecification
s 在指南中描述)你不应该关心将进程 ID、后端名称和其他东西传递给 find_element
每次。
P.S。在我看来,SWAPY 可以得到显着改进,但去年没有维护。我希望将来用更小的代码库和 MS UI 自动化支持重新编写它。但目前全自动脚本生成器优先级更高
编辑:
此按钮 w_open['SplitButton6'].draw_outline()
可能会被检测为一般 HwndWrapper
对象而不是 ButtonWrapper
。你可以用这个检查它:
w_open['SplitButton6'].wrapper_object()
这正是入门指南(您说您已阅读)中所写的内容。
幸运的是,您可以对任何控件使用方法 .click_input()
:
w_open['SplitButton6'].click_input()
我可以说更多:WindowSpecification 没有 click
方法。这是动态实例化的 ButtonWrapper
方法。例如,这些语句的工作方式相同(但 Python 可以隐藏 .wrapper_object()
调用):
w_open['SplitButton6'].wrapper_object().click_input()
w_open['SplitButton6'].click_input()
Getting Started Guide 中也有描述。请阅读整个指南。你会发现很多有用的高级东西。如果仍然不清楚,我可以就一些极端情况提出建议。
我正在尝试使用 pywinauto 和 Python 3.6 自动化一个简单的应用程序。该应用程序有一个 Windows "Open" 对话框,我想单击 "Cancel" 按钮:
我使用 SWAPY 获取按钮的 class_name 和 control_id 属性。
现在的问题是,当我使用这些参数调用 find_element() 方法时,它会引发 ElementNotFoundError。这是我的代码:
cancel_button = pywinauto.findwindows.find_element(class_name="button", control_id=2)
我试过(class_name="button", control_id="2")
、(class_name="Button", control_id=2)
,但它们都给出相同的错误。我试图在此对话框中找到的任何其他元素都会出现同样的问题。
那么如何使用从 SWAPY 读取的属性呢?我没有发现官方的 pywinauto 文档非常有用。很多东西都没有解释清楚。
编辑: 我决定不使用 find_elements 方法,而是使用 find_windows() 来获取“打开”对话框的句柄。
w_open_handle = pywinauto.findwindows.find_windows(title=u'Open', class_name='#32770')[0]
然后我使用这个句柄得到一个 WindowSpecification 对象:
w_open = app.window_(handle=w_open_handle)
然后我打电话给:
w_open['Cancel'].click()
这行得通。现在我想在 "File name:" 编辑框中输入一个文件名,然后单击打开按钮打开该文件。所以我这样做:
w_open['File name:'].type_keys("abc.txt")
这行得通。我使用 print_control_identifiers() 打印出控件标识符,并获得了“打开”按钮的名称。所以使用 draw_outline() 我在它外面画了一个边界,它显示了正确的按钮。
w_open['SplitButton6'].draw_outline()
但是在 'SplitButton6' 上调用 .click() 方法会引发 WindowSpecification class 没有 'click' 方法 错误。知道是什么原因造成的吗?该错误似乎具有误导性,因为 WindowSpec class 确实有一个 .click 方法。
正确答案是您错过了 top_level_only=False
(默认情况下是 True
,因为更高级别 API 至少调用它两次)。那么您可能有 2 个控件符合此条件(可能来自不同的应用程序)。 find_element
是低级函数。不推荐直接使用(代码太长,有很多坑,上级考虑到了API)。
>>> pywinauto.findwindows.find_element(class_name="Button", control_id=2, top_level_only=False)
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
File "...\pywinauto\findwindows.py", line 98, in find_element
raise exception
ElementAmbiguousError: There are 2 elements that match the criteria {'class_name': 'Button', 'control_id': 2, 'top_level_only': False}
>>> pywinauto.findwindows.find_element(class_name="Button", title='Cancel', top_level_only=False)
<win32_element_info.HwndElementInfo - 'Cancel', Button, 395554>
使用更高级别 API(Application
对象和 WindowSpecification
s 在指南中描述)你不应该关心将进程 ID、后端名称和其他东西传递给 find_element
每次。
P.S。在我看来,SWAPY 可以得到显着改进,但去年没有维护。我希望将来用更小的代码库和 MS UI 自动化支持重新编写它。但目前全自动脚本生成器优先级更高
编辑:
此按钮 w_open['SplitButton6'].draw_outline()
可能会被检测为一般 HwndWrapper
对象而不是 ButtonWrapper
。你可以用这个检查它:
w_open['SplitButton6'].wrapper_object()
这正是入门指南(您说您已阅读)中所写的内容。
幸运的是,您可以对任何控件使用方法 .click_input()
:
w_open['SplitButton6'].click_input()
我可以说更多:WindowSpecification 没有 click
方法。这是动态实例化的 ButtonWrapper
方法。例如,这些语句的工作方式相同(但 Python 可以隐藏 .wrapper_object()
调用):
w_open['SplitButton6'].wrapper_object().click_input()
w_open['SplitButton6'].click_input()
Getting Started Guide 中也有描述。请阅读整个指南。你会发现很多有用的高级东西。如果仍然不清楚,我可以就一些极端情况提出建议。