UI 自动化测试selenium(二)

css选择器

CSS选择器的调试方式(也就是开发者模式的Console):

$("[id='title']")

有的需要输入两个$$

$$("[id='title']")

##基础使用
#****************************************************************
# 选择所有div标签
driver.find_elements(By.CSS_SELECTOR, "div")
# 选择ID为modal的元素
driver.find_element(By.CSS_SELECTOR, "#modal")
# 选择class类为new的元素
driver.find_element(By.CSS_SELECTOR, ".new")
# 选择href类内容为/的元素
driver.find_element(By.CSS_SELECTOR, '[href="/"]')

er中用法示例的表格:

类型

表达式

示例

标签

标签名

driver.find_elements(By.CSS_SELECTOR, "div")

.class属性值

driver.find_element(By.CSS_SELECTOR, ".new")

ID

#id属性值

driver.find_element(By.CSS_SELECTOR, "#modal")

属性

[属性名=‘属性值’]

driver.find_element(By.CSS_SELECTOR, '[href="/"]')

进阶使用

类型

格式

示例

父子关系+顺序

元素:nth-child(n)

$('#form>input:nth-child(2)')

父子关系+标签类型+顺序

元素:nth-of-type(n)

$('#form>input:nth-of-type(1)')

类型

格式

在console中的写法示例

并集

元素,元素

$('.bg,.s_ipt_wr,.new-pmd,.quickdelete-wrap')

邻近兄弟(了解即可)

元素+元素

$('.soutu-btn+input')

兄弟(了解即可)

元素1~元素2

$('.soutu-btn~i')

父子

元素>元素

$('#s_kw_wrap>input')

后代

元素 元素

$('#form input')

##进阶使用
#****************************************************************
driver.find_element(By.CSS_SELECTOR, 'div.footer1 > span.copyright')
# 或者使用类选择器方式
driver.find_element(By.CSS_SELECTOR, '.footer1 > .copyright')
# 多元素选择,选取类名为footer1的元素和类名为copyright的元素
driver.find_elements(By.CSS_SELECTOR, '.footer1, .copyright')
# 选取第2个子元素且为<code>标签的元素
driver.find_element(By.CSS_SELECTOR, 'code:nth-child(2)')
# 选取第2个<code>标签类型的元素
driver.find_element(By.CSS_SELECTOR, 'code:nth-of-type(2)')
# 选取<code>标签之后紧跟的第一个<div>标签
driver.find_element(By.CSS_SELECTOR, 'code + div')
# 选取<code>标签之后所有的<div>标签
driver.find_elements(By.CSS_SELECTOR, 'code ~ div')

##进阶使用
#****************************************************************
# 选择class类为new、button的元素(html中是class=new button)需要把空格换成.
driver.find_element(By.CSS_SELECTOR, ".new.button")
# 类名为navbar-brand并且href为/的a标签
driver.find_element(By.CSS_SELECTOR, 'a.navbar-brand[href="/"]')
# 选择<a>标签且href属性为"/"的元素
driver.find_element(By.CSS_SELECTOR, 'a[href="/"]')

# 选择ID为modal的元素内部的所有div元素
driver.find_elements(By.CSS_SELECTOR, '#modal div')
# 类名中包含modal的元素(所有含 modal 的 class)
driver.find_elements(By.CSS_SELECTOR, '[class*="modal"]')
# 所有class属性以mo开头的a元素
driver.find_elements(By.CSS_SELECTOR, 'a[class^="mo"]')
# 所有class属性以al结尾的a元素
driver.find_elements(By.CSS_SELECTOR, 'a[class$="al"]')
# 同时具有多个属性的div元素
driver.find_element(By.CSS_SELECTOR, 'div[class="modal"][role="dialog"]')
# 类名为footer1的div元素下的直接子元素,其类名为copyright的span元素

Xpath选择器

Xpash本来是在XML文档中进行检索的语言

使用的是路径表达式

支持显示文本定位(html中黑色文字)

Xpath的调试方式:
$x("表达式")

表达式

结果

示例

/

从该节点的子元素选取

$x("/")

//

从该节点的子孙元素选取

$x("//*")

*

通配符

$x("/*")

nodename

选取此节点的所有子节点

$x("//div")

..

选取当前节点的父节点

$x('//*[@id="site-logo"]/..')

@

选取属性

$x('//*[@id="site-logo"]')

实现了从子查父,也能从父查子,非常方便,基本上能解决99%的定位难题

# 获取[@id='ember21']节点下的所有的li元素 
$x("//*[@id='ember21']//li") 
# 获取[@id='ember21']节点下所有的节点的第一个li元素 
$x("//*[@id='ember21']//li[1]")

XPath 表达式

描述

示例

//div[text()=‘3’]

搜索显示特定文字的div元素

$x("//div[text()='3']")

/html/div/span/h1

按给定顺序寻找路径

$x("/html/div/span/h1")

//div//span

所有的div下面的所有span

$x("//div//span")

//*[@class=‘cawada’]

搜索具有特定class属性的元素

$x("//*[@class='cawada']")

//*[contains(@style,‘color’)]

模糊搜索style属性包含color的元素

$x("//*[contains(@style,'color')]")

//*[starts-with(@style,‘color’)]

搜索style属性以color开始的元素

$x("//*[starts-with(@style,'color')]")

//p[2]

搜索第二个p元素

$x("//p[2]")

//div/p[2]

搜索div元素的第二个直接子元素p

$x("//div/p[2]")

//p[last()-1]

搜索倒数第二个p元素

$x("//p[last()-1]")

//p[position()<=2]

搜索位置在前两位的p元素

$x("//p[position()<=2]")

//[@class=‘xx’]/following-sibling::

搜索具有特定class的元素的所有兄弟节点

$x("//*[@class='xx']/following-sibling::*")

following-sibling::*

选择前面的兄弟节点

$x("following-sibling::*")

/input[@name='passward' and @pwd='123456']

使用and分割,多属性查找(or满足一个即选择)

$x("/input[@name='passward' and @pwd='123456']")

//*[@id=‘china’]/…

选择具有特定id的元素的父节点

$x("//*[@id='china']/..")

显式等待原理

WebDriverWait类

先看看传入什么参数:

参数:

1.实例化的浏览器驱动

2.最长等待时间

3.轮询等待时间,默认为0.5s

until方法

注意!这个method传的是函数对象!

def func(driver):#这里为什么要传参?看看下一图片的value=method(self._driver)
	print("123")
WebDriverWait(driver,10,1).until(func) # 这里不要使用func()!
# 这里因为没有设置func的返回值,所以会一直轮询,直到最大等待时间

实现方法:

我们来看看之前写的简单的显式等待:

from selenium.webdriver.support import expected_conditions #导入expected_conditions
def wait_until(): 
 	driver = webdriver.Chrome() 
	driver.get("https://www.baidu.com") 
	WebDriverWait(driver, 10).until( expected_conditions.element_to_be_clickable( (By.CSS_SELECTOR, '#success_btn'))) 
	driver.find_element(By.CSS_SELECTOR, "#success_btn").click()

expected_conditions.element_to_be_clickable()

这个方法是什么?

从导入信息可以看出来是来自elenium.webdriver.support的方法,实现的功能是元素如果可以点击则返回True

这里返回的target其实是WebElement类型:

所以可以省略为:

from selenium.webdriver.support import expected_conditions #导入expected_conditions
def wait_until(): 
 	driver = webdriver.Chrome() 
	driver.get("https://www.baidu.com") 
	WebDriverWait(driver, 10).until( expected_conditions.element_to_be_clickable( (By.CSS_SELECTOR, '#success_btn'))).click()

support库里的确有很多的方法,但是也还有有局限性,我们得学会如何自定义显式等待:

显示等待其实可以理解为一个循环,直到你的函数返回True或者不为None的值

现在有一个场景,你需要设计一个显式等待来实现不断点击,直到你弹窗出现才停止

# 需求:连续点击,直到弹窗出现
# 先明确参数, 1、点击的参数  2、弹窗的参数
# 再明确返回值:如果出现弹窗返回True或者元素,没有弹窗返回None
def func(click_arg, pop_arg):
    def _predicate(driver):#头和尾巴是直接从support库中copy过来
        driver.find_element(*click_arg).click()#点击
        return driver.find_element(*pop_arg)#返回
    return _predicate

def test_wait_until():
    driver = webdriver.Chrome()
    driver.get("https://URLTEST")
    WebDriverWait(driver, 10).until(func((By.CSS_SELECTOR, '#primary_btn'),(By.XPATH, '//span[text()="该弹框点击两次后才会弹出"]')))
    time.sleep(5)

其实WebDriverWait源码中还有个not_until,这里不展开细讲,可以自行研究。