美文网首页
元素定位

元素定位

作者: Cc_Leo | 来源:发表于2019-12-03 18:22 被阅读0次

    一、直接调用WebDreiver的方法

    driver.find_element_by_xpath

    二、重写webdriver的find方法

        def find_elements_xpath(self, *loc):
            driver = self.driver
    
            """
            定位元素,定位正确后返回元素的信息,外部调用传入元组参数必须有*,
            例如:
            find_element(*self.native_caixun)
            :param loc: 元组类型,结构必须是(By.NAME, u'财讯')
            :return: element
            """
            try:
                element = WebDriverWait(driver, 20, 0.2).until(lambda driver: driver.find_elements_by_xpath(*loc))
                return element
            except Exception as e:
                print(current_time() + 'Error details :%s' % (e.args[0]))
    

    一般通过xpath和id就能定位绝大多是元素

    三、使用JS定位

    某些元素在js里面,通过xpath不易定位,此时可以考虑使用JS去定位元素。注意Elements返回的数组,Element返回的是单个元素

    js = 'document.getElementsByName("pm/projBuild")[0].click()'
    # 使用下列方法执行js
    self.driver.execute_script(js)
    

    JS的document属性,定位元素的方法

    document.getElementById()
    # 返回指定id的元素
    document.getElementsByName()
    # 返回带有指定名称的对象的集合。注:返回一个数组
    document.getElementsByTagName()
    # 返回带有指定标签名的对象的集合。注:返回一个数组。
    document.getElementsByClassName()
    # 返回文档中所有指定类名的元素集合,作为 NodeList 对象:返回一个数组。
    

    实现页面滚动

    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    

    以上语句实现了拉动页面到底部的功能,其中window.scrollTo(左边距,上边距)是JavaScript中用于设置浏览器窗口滚动条的水平和垂直位置的代码。

    text = "input text"
    driver.execute_script("var obj=document.getElementById('text'); obj.value=' " + text + " ';")
    

    以上代码实现了对id='text'的对话框(不能通过send_keys()输入文本)输入文本的操作

    video = driver.find_element_by_xpath("body/Section[1]/div/video")
    url = driver.execute_script("return arguments[0].currentSrc;", video) # url是文件播放地址
    driver.execute_script("return arguments[0].play()", video) # 播放视频
    sleep(15)   # 播放15秒钟
    driver.execute_script("arguments[0].pause()", video) #暂停视频
    

    以上实现了HTML5视屏<video>标签的部分测试,更多内容参考HTML DOM Video对象
    其中arguments是JavaScript的内置对象。因为将video对象传给了arguments[0],所以arguments[0]相当于JavaScript脚本的document.getElementsByTagName("video")。JavaScript不支持重载,使用arguments对象可以模拟函数重载效果。

    四、页面还没有加载出来,就对页面上的元素进行的操作

    因为加载元素延时造成的脚本失败,我们可以通过设置等待时间来提升自动化脚本的稳定性。
    1:WebDriverWait() 显示等待。等待单个的元素加载,通常配合until()、until_not()方法使用。

    WebDriverWait(driver,timeout,poll_frequency=0.5,ignored_exceptions=None)
    """
    driver - 传入WebDriver实例,必填
    timeout - 最长等待时间,必填
    poll_frequency - 调用`until`/`until_not`方法的时间间隔,默认为0.5秒,可省。
    ignored_exceptions - 忽略异常,默认仅包含NoSuchElementException,可省。
    """
    
    WebDriverWait(driver,10).until(method,message='')     '等待目标出现'
    WebDriverWait(driver,5,1).until_not(method,message='')    '等待目标消失'
    """
    method - 必填。
    message - 默认为空,可省。如果超时,抛出TimeoutException,返回message信息。
    """
    # 如下:
    WebDriverWait(driver, 超时时长, 调用频率, 忽略异常).until(可执行方法, 超时时返回的信息)
    
    WebDriverWait(driver,5,1).until(expected_conditions.presence_of_element_located(By.ID,'kw'))
    

    最长等待时间为5s,每隔1秒检查一次id='kw'的元素是否被加载在DOM树里(并不代表该元素一定可见)。最常用的methodexpected_conditions类提供的预期条件判断。

    is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleException)).until_not(lambda x: x.find_element_by_id('someId').is_displayed())
    

    最长等待时间为30s,每隔1秒检查一次id='someId'的元素是否从DOM树里消失,忽略默认异常信息8NoSuchElementException 和指定的异常信息ElementNotVisibleException*。此处匿名函数lambda的用法具体参考Python语法。
    2driver.implicitly_wait(秒) 隐式等待。全局等待,对所有元素设置超时时间,等待页面的加载,因此只需要设置一次即可。这里的时间是最长等待时间(非固定等待时间)。
    3sleep(秒) 线程等待。休眠固定的时间,使用时需要先引入time模块的sleep方法from time import sleep

    五、元素被遮挡,不可用,不可见

    1driver.maximize_window() 由于窗口大小改变引起的页面元素布局发生变化,被测元素被遮挡,可以先将窗口最大化,再进行元素定位。
    2.is_enabled() 由于业务原因元素在某些情况下不可用(元素属性disabled,灰显),首先检查测试步骤是否符合业务逻辑,其次确认是否为业务流程上的Bug。
    3.is_displayed() 对于属性不一定可见的元素,在定位前首先判断其属性是否可见,是否被隐藏。
    4:由于布局不合理导致的元素被遮盖、或是元素本身缺失引起的无法定位问题属于Bug,可以提给开发让其改进。

    六、WebDriver无法操作Windows控件

    1.使用AutoIt定位控件,编写脚本,编译为exe,然后调用python执行os.system("D:\\upfile.exe")
    2.使用win32模块调用windwos的API

    # 上传文件
    def upload(file, title=u'选择要上载的文件,通过: 192.168.1.248'):
        dialog = win32gui.FindWindow('#32770', title)
        ComboBoxEx = win32gui.FindWindowEx(dialog, 0, 'ComboBoxEx32', None)
        ComboBox = win32gui.FindWindowEx(ComboBoxEx, 0, 'ComboBox', None)
        Edit = win32gui.FindWindowEx(ComboBox, 0, 'Edit', None)
        button = win32gui.FindWindowEx(dialog, 0, 'Button', None)
        time.sleep(0.5)
        win32gui.SendMessage(Edit, win32con.WM_SETTEXT, 0, file)
        time.sleep(0.5)
        win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button)
        time.sleep(0.5)
    

    上述代码实现了对windows上传文件窗口的操作(需要先试用用AutoIt或spy++定位控件的窗口名和句柄)
    3.使用pywinauto

    from pywinauto import application
    import SendKeys
    import time
    
    class Pywin(object):
        """
        pywin framwork main class
        tool_name : 程序名称,支持带路径
        windows_name : 窗口名字
        """
        SLEEP_TIME = 1
    
        def __init__(self):
            """
            初始化方法,初始化一个app
            """
            self.app = application.Application()
    
        def run(self, tool_name):
            """
            启动应用程序
            """
            self.app.start_(tool_name)
            time.sleep(1)
    
        def connect(self, window_name):
            """
            连接应用程序
            app.connect_(path = r"c:\windows\system32\notepad.exe")
            app.connect_(process = 2341)
            app.connect_(handle = 0x010f0c)
            """
            self.app.connect_(title = window_name)
            time.sleep(1)
    
        def close(self, window_name):
            """
            关闭应用程序
            """
            self.app[window_name].Close()
            time.sleep(1)
    
        def max_window(self, window_name):
            """
            最大化窗口
            """
            self.app[window_name].Maximize()
            time.sleep(1)
    
        def menu_click(self, window_name, menulist):
            """
            菜单点击
            """
            self.app[window_name].MenuSelect(menulist)
            time.sleep(1)
    
        def input(self, window_name, controller, content):
            """
            输入内容
            """
            self.app[window_name][controller].TypeKeys(content)
            time.sleep(1)
    
        def click(self, window_name, controller):
            """
            鼠标左键点击
            example:
            下面两个功能相同,下面支持正则表达式
            app[u'关于“记事本”'][u'确定'].Click()
            app.window_(title_re = u'关于“记事本”').window_(title_re = u'确定').Click()
            """
            self.app[window_name][controller].Click()
            time.sleep(1)
    
        def double_click(self, window_name, controller, x = 0,y = 0):
            """
            鼠标左键点击(双击)
            """
            self.app[window_name][controller].DoubleClick(button = "left", pressed = "",  coords = (x, y))
            time.sleep(1)
    
        def right_click(self, window_name, controller, order):
            """
            鼠标右键点击,下移进行菜单选择
            window_name : 窗口名
            controller:区域名
            order : 数字,第几个命令
            """
            self.app[window_name][controller].RightClick()
            for down in range(order):
                    SendKeys.SendKeys('{DOWN}')
                    time.sleep(0.5)
            SendKeys.SendKeys('{ENTER}')
            time.sleep(1)
    
    if __name__ ==  "__main__":
        app = Pywin()
        # 记事本例子
        tool_name = "notepad.exe"
        # 通过Spy++ 获取window_name,即标题文本
        window_name = u"无标题 - 记事本"
        menulist = u"帮助->关于记事本"
        # 通过Spy++ 获取controller,即窗口类名
        controller = "Edit"
        content = u"johnny"
        window_name_new = content + ".txt"
        # 启动程序,记事本只能开一个
        app.run(tool_name)
        app.connect(window_name)
        app.max_window(window_name)
        app.menu_click(window_name,menulist)
        app.click(u'关于记事本', u'确定')
        app.input(window_name,controller,content)
        # Ctrl + a 全选
        app.input(window_name,controller,"^a")
        # 选择复制
        app.right_click(window_name,controller,3)
        #选择粘贴
        app.right_click(window_name,controller,4)
        SendKeys.SendKeys('{ENTER}')
        # Ctrl + v 粘贴
        app.input(window_name,controller,"^v")
        # Ctrl + s 保存
        app.input(window_name,controller,"^s")
        # 输入文件名
        app.input(u"另存为",controller,content)
        # 保存
        app.click(u"另存为","Button")
        try:
            app.click(u"确认另存为","Button")
        except:
            pass
        finally:
            app.close(window_name_new)
    

    七、页面元素失去焦点导致脚本运行不稳定

    1:遇到脚本不稳定,有时会失去焦点导致测试失败的情况下,可以先切到焦点元素再进行操作。driver.switch_to.active_element
    注意.active_element后面不带括号()。
    下面是一个参考案例

    '最初的 “右击鼠标 → 新建文件夹 → 输入文件夹名称” 的代码'
    l = driver.find_element_by_id('pm_treeRoom_1_span')
    ActionChains(driver).context_click(l).perform()
    driver.find_element_by_class_name('fnew').click()
    time.sleep(2)
    driver.find_element_by_xpath('//*[@id="pm_treeRoom_1_ul"]/li[...]').send_keys('filename')
    time.sleep(2)
    

    结果这种操作总会导致输入框失去焦点,直接消失,更不能send_keys进去了,直接报错。

    '修改后的代码如下'
    driver.find_element_by_class_name('fnew').click()
    time.sleep(2)
    driver.switch_to.active_element.send_keys('filename')
    time.sleep(2)
    

    相关文章

      网友评论

          本文标题:元素定位

          本文链接:https://www.haomeiwen.com/subject/acocgctx.html