pywinauto:Windows桌面应用自动化测试(五)

前言

上一篇文章地址:

pywinauto:Windows桌面应用自动化测试(四)_pywinauto以管理员身身份start-CSDN博客

下一篇文章地址:

暂无

一、实战常用方法

1、元素的文本获取

window_text() 方法可以获取窗口或控件的文本内容。

texts() 方法返回控件的所有文本内容,以列表形式表示。适用于多文本控件,如组合框或列表框。

.wrapper_object().window_text()方法,需要将控件包装成特定类型的对象,以便获取更多属性和方法。

.legacy_properties()['Value']方法,对于某些特定的 UIA 控件,可以通过 legacy_properties 获取其属性值。

.element_info.name.element_info.rich_text方法,通过 element_info 可以获取更多控件的信息。

.get_value() 方法,对于一些特定类型的控件,可以使用 get_value() 方法获取其值。

from pywinauto import Application

# 连接到应用程序
app = Application(backend='uia').start('notepad.exe')
dlg = app['Untitled - Notepad']

# 获取编辑控件
edit = dlg.child_window(class_name='Edit')

# 使用不同的方法获取文本内容

# 方法1: window_text()
text = edit.window_text()
print("window_text():", text)

# 方法2: texts()
texts = edit.texts()
print("texts():", texts)

# 方法3: wrapper_object().window_text()
edit_wrapped = edit.wrapper_object()
text_wrapped = edit_wrapped.window_text()
print("wrapper_object().window_text():", text_wrapped)

# 方法4: legacy_properties()['Value']
value = edit.legacy_properties().get('Value', '')
print("legacy_properties()['Value']:", value)

# 方法5: element_info.name
name = edit.element_info.name
print("element_info.name:", name)

# 方法6: get_value()
value_get = edit.get_value()
print("get_value():", value_get)
2、元素点击不到

(1)点击区域不在中心点

如下图,这是inspect给出的元素范围,这种情况是因为点击区域不在中心点,所以点击之后没反应。因此,通过以下方法是点击不到的。

    def enter_website(self):
        about_app = Application(backend='uia').connect(title="Form")  # Form
        about_win = about_app.window(title='Form')
        about_win.child_window(title='进入官网').click_input()

我们需要使用上一节说到的点击方式进行点击:

    def enter_website(self):
        def _element_num_of_copies(element, fraction):
            print(element.rectangle(), type(element.rectangle()))
            rectangle = element.rectangle()
            L, T, R, B = rectangle.left, rectangle.top, rectangle.right, rectangle.bottom
            width = R - L
            height = B - T
            x = int(L + width * fraction)
            y_center = int(T + height / 2)
            return (x, y_center)

        about_app = Application(backend='uia').connect(title="Form")  # Form
        about_win = about_app.window(title='Form')
        # about_win.child_window(title='进入官网').click_input()
        element = about_win.child_window(title='进入官网')
        rectangle = _element_num_of_copies(element, 1/5)
        click(coords=rectangle)

(2)元素没来得及显示

有些元素需要点击按钮才会显示出来,这种情况下没那么快找到元素,此时需要在显示前加适当延时。

    def open_about(self):
        time.sleep(3)
        help_app = Application(backend='uia').connect(title='Form')
        help_win = help_app.window(title='Form')
        help_win.child_window(title="关于").click_input()

或者比较优雅的方式,如下操作:

    def open_about(self):
        help_app = Application(backend='uia').connect(title='Form')
        help_win = help_app.window(title='Form')
        _about = help_win.child_window(title="关于")
        _about.wait('visible', timeout=10)  # 等待显示
        _about.click_input()

一般来讲,如果窗口存在,则元素一般能显示,因此还可以这样改:

使用 lambda 表达式返回 help_win 对象本身来解决等待窗口出现的问题,但关键在于需要一个检查函数,能够在 wait_until_passes 方法中动态地检查条件,并在满足条件时返回所需的对象。其中 .exists()是用于判断元素是否存在的方法。

    def open_about(self):
        help_app = Application(backend='uia').connect(title='Form')
        # help_win = help_app.window(title='Form')
        # 使用 wait_until_passes 等待关于窗口出现
        from pywinauto import timings
        timings.wait_until_passes(10, 0.5, lambda :help_app.window(title='Form').exists(timeout=1))
        _about = help_win.child_window(title="关于")
        _about.click_input()
3、窗口定位不到

如上节所诉,得通过inspect来查看定位窗口的层级,如果是二级窗口,得采用window的方法,如果是三级及其往后的层级窗口,可以使用child_window来获取。

这个需要特别注意,因为如下窗口都可能是二级窗口。

4、当inspect不好用时

以下2种方式获取的元素信息是不一致的,而且pywinauto 目前并不支持 msaa 作为后台,但可以使用win32或uia后台技术尝试访问。一般使用uia也可以访问msaa后台,元素获取比win32多一些。但是,当 msaa 作为后台时,通过inspect的uia获取元素信息是不完整的,此时需要使用 .print_control_identifiers() 方法打印, 对于pywinauto来说,print_control_identifiers()是最准的。

        app = Application(backend='uia').connect(title_re=".*666.*")
        window = app.window(title_re=".*666.*")
        window.print_control_identifiers()

5、元素模糊匹配

元素其实支持模糊匹配,可以通过title_re实现,示例如下:

        app = Application(backend='uia').connect(title_re=".*666.*")
        window = app.window(title_re=".*666.*")
6、为什么wait_until_passes方法需要这个函数 exists
    def exists(self, timeout=None, retry_interval=None):
        """
        Check if the window exists, return True if the control exists

        :param timeout: the maximum amount of time to wait for the
                    control to exists. Defaults to ``Timings.exists_timeout``
        :param retry_interval: The control is checked for existance this number
                    of seconds. ``Defaults to Timings.exists_retry``
        """
        # set the current timings -couldn't set as defaults as they are
        # evaluated at import time - and timings may be changed at any time
        if timeout is None:
            timeout = Timings.exists_timeout
        if retry_interval is None:
            retry_interval = Timings.exists_retry

        # modify the criteria as exists should look for all
        # windows - including not visible and disabled
        exists_criteria = self.criteria[:]
        for criterion in exists_criteria:
            criterion['enabled_only'] = False
            criterion['visible_only'] = False

        try:
            self.__resolve_control(exists_criteria, timeout, retry_interval)

            return True
        except (findwindows.ElementNotFoundError,
                findbestmatch.MatchError,
                controls.InvalidWindowHandle,
                controls.InvalidElement):
            return False

exists 方法用于检查控件是否存在,它的实现细节涉及到如何在一定时间内不断尝试查找控件,并返回是否找到控件的结果。而wait_until_passes 方法实际上是用于重复尝试某个操作,直到操作成功或超时。在 pywinauto 中,wait_until_passes 方法用于确保操作可以在给定时间内成功完成,而 exists 方法则是在这个过程中判断控件是否存在。

(1)exists 方法的源码分析

参数设置:timeout:指定等待控件存在的最大时间。retry_interval:指定每次检查控件存在与否的时间间隔。

Criteria 修改:将控件的 enabled_onlyvisible_only 设置为 False,这样可以找到所有控件,不管它们是否可见或是否启用。

查找控件:使用 self.__resolve_control 方法尝试找到控件。如果在超时时间内找不到控件,将抛出异常。处理了 findwindows.ElementNotFoundErrorfindbestmatch.MatchErrorcontrols.InvalidWindowHandlecontrols.InvalidElement 这几种可能的异常,捕获异常后返回 False

(2)wait_until_passes 方法的作用

wait_until_passes 是用于重复尝试某个操作,直到成功或超时。这个方法通常用来等待某个控件的存在或某个条件的满足。在调用 exists 方法时,通常需要通过 wait_until_passes 来确保控件在某个时间段内是可用的。例如,确保一个窗口或控件在特定时间内被成功加载。

(3)为什么 wait_until_passes 需要 exists 方法

wait_until_passes 方法通常会用 exists 方法来判断控件是否存在。如果你使用 wait_until_passes 来等待一个控件的存在,它会重复调用 exists 方法直到控件存在或超时。这样可以处理控件加载时间不确定的情况。

  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lion King

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值