元素定位

2019-12-03  本文已影响0人  Cc_Leo

一、直接调用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)
上一篇下一篇

猜你喜欢

热点阅读