目前工作中使用的UI自动化框架:pytest+selenium。selenium中有几个概念,刚刚了解,记录下:
selenium-webdriver
selenium-webdriver和webdriver是两个东西。前者是selenium基于浏览器原生API封装的库,后者则是浏览器厂商提供的驱动软件
webdriver
webdriver是W3C的一个标准,是一个远程控制协议。通过该协议,每个浏览器均提供了跨平台和跨语言的方式来远程操作浏览器;同时也提供一系列接口访 问和操作DOM,进而控制浏览器的行为。
换句话说,W3C联盟要求的浏览器厂商支持的webdriver协议,为我们利用脚本操控浏览器留下了后门
W3C :这是一个联盟,负责管理行业标准之类的
总结:selenium通过指定元素驱使webdriver,再有webdriver和浏览器内核进行模拟操作。但不同浏览器对web元素的操作和呈现会有差异,webdriver实现则不同,直接导致selenium-webdriver也要分浏览器处理相同操作
https://www.w3.org/TR/webdriver1/
selenium源码分析之webdriver: https://blog.csdn.net/ant_ren/article/details/7970793(还未仔细研读,本周安排) https://segmentfault.com/a/1190000017841619 https://www.lambdatest.com/blog/selenium4-w3c-webdriver-protocol/ https://python-selenium-zh.readthedocs.io/zh_CN/latest/ 新的selenium4看起来很棒,这是索引: https://www.lambdatest.com/blog/selenium4-w3c-webdriver-protocol/
HTML简介
操作元素的UI自动化是立足于HTML文档的,首先大致了解下HTML文档
HTML(超文本标记语言),通过 标记标签 (尖括号括起来的词,如****,便可认为是一个标签)创建网页。所以,HTML可以理解为是一组标签;标签属性;标签文本的集合文件,如下:
<!DOCTYPE HTML> # DOCTYPE字样告诉浏览器这是一个HTML文档
<!--...--> # HTML单行注释
<html> # <html>表示网页开始,网页内容都是从html开始
<body> # head负责元数据,body加载网页内容
什么是标签?
标签是使用<>括起来的词,如
<html>
,它基本成对出现,也有少部分单独出现,如
<br>、<hr>
什么是元素?
标签和内容一起构成元素,
My Heading
即是一个元素 ,“My Heading”是元素的内容。元素名称使用时不区分大小写
什么是元素属性?
元素属性是写在起始标签,或者单个标签中修饰对应元素的键值对;一个元素可以有多个属性,通过一个或多个空格分隔;属性不能书写在结束标签中
示例中,p元素具有两个属性,class和id
开始标签 元素内容 结束标签 元素属性
<p>
This is a par
</p>
<a href="https://link.shangyexinzhi.com/url?a.htm" rel="nofollow" >
This is a link
</a>
href="https://link.shangyexinzhi.com/url?a.htm" rel="nofollow"
<br />
什么是布尔属性? UI界面中输入框/复选框灰化不可用使用的情况,这类一般是使用disabled(布尔属性)标记,disabled属性阻止用户输入数据。 disable正常是不需要赋值的,直接声明即可,但也有研发通过分配空字符串或者将属性值设置为属性名称达到相同目的
Enter what you like: <input disabled> # 直接声明 <input disabled=""> <input disabled="disabled">
HTML简介:https://www.w3cschool.cn/html/html-css-index.html
selenium API
根据定位元素的方式,selenium提供了很多API
<html> <body> <a id="result_logo" href="https://link.shangyexinzhi.com/url?%2Findex.html" rel="nofollow" > <form id="form" class="fm" name="f" action="/s">
定位方式 定位单个元素API 定位多个元素API 简单示例
id:根据元素id属性定位 find_element_by_id() 前面element换成elements driver.find_element_by_id("result_logo") # 可定位到id="result_logo"的a元素
name:根据元素name属性定位 find_element_by_name() driver.find_element_by_name("f") # 可定位到name="f"的元素
class_name:根据元素class属性定位 find_element_by_class_name() driver.find_element_by_class_name("fm") # 可定位到class_name="fm"的元素
tag_nane:根据元素标签名称定位 find_element_by_tag_name() driver.find_element_by_tag_name("a") # 可定位到名称为a的标签
link_text:超链接定位 find_element_by_link_text() driver.find_element_by_link_text("index") # 链接文本定位超链接,匹配包含文本为index的超链接标签
partial_link_text:超链接部分字符匹配定位 find_element_by_partial_link_text() driver.find_element_by_link_text("in") # 部分文字匹配超链接
xpath find_element_by_xpath()
css selector find_element_by_css_selector()
find_element方法,返回第一个匹配的元素;find_elements将当前页面所有适配元素,封装为列表返回。若无匹配元素,抛出 NoSuchElementException 异常。实际工作中,元素具有唯一属性并不多见,大部分定位使用xpath或者css_selector
个人向,好的定位习惯:
元素定位尽量避免带入层级结构,转而使用相对关系,可一定程度减少维护
减少使用xpath,使用css增加脚本执行效率:xpath定位,webdriver会遍历整个元素树,生成xml格式数据,然后再进行xpath查找
XPATH定位
什么是XPATH定位?
xpath(xml路径语言)并不是selenium专用的定位方式,起初使用在xml文档中定位信息,而HTML文档的层次结构与xml天然一致,因而也可以使用xpath方式在HTML中定位元素
什么是节点?
节点可以简单理解为一层层的树结构,在xpath的世界中,遍历对象(如HTML文件)是一个节点树
<html> <head> <title>DOM 教程</title> </head> <body> <h1 href="index.html">DOM 第一课</h1> <p>Hello world!</p> </body> </html>
该HTML转化为节点树为:
新知达人, 一篇关于UI自动化的持续总结
img
节点树包含7种类型的节点:元素;属性;文本;命名空间;处理指令;注释以及文档节点。比较常用于定位的是 元素;属性;文本
xpath通过语法( 节点路径表达式;xpath轴 )在节点树中找到对应节点。UI中,最小颗粒是元素,因此下文中的节点和元素可视为同义词
节点路径表达式
路径表达式是通过元素层级挑选目标元素的一种方式: 节点是沿着路径可直接选取,或者沿着路径后通过步进(step)选取
绝对路径:
每个路径表达式都具有两种写法:绝对路径表达式;相对路径表达式
绝对路径,都从根节点元素开始
/html/body/div[1]/div[1]/div[5]/div/div/form/span/input[1] # 绝对路径 //input[@id='kw'] # 相对路径
相对路径:
//开头,从文档中直接选择后续语句中匹配的节点,且不考虑位置
使用/作为路径分割符
.表示当前节点;..表示当前节点的父节点
//nodename,//input,选取所有input标签
@选取属性,text()选择文本,这两种通常使用在谓语中
谓语 :根据路径得到节点集合后,进一步筛选的方式,谓语写在[]中
支持and和or运算符;使用“|”运算符,您可以选取若干个路径
通配符: :匹配任何元素节点;@ :匹配任何属性节点
chrome-console验证元素: $x(“xpath”)
//input # 所有input标签 //input/. # .当前节点,结合//input表示,选择当前页面的所有input标签 //input/.. # ..当前节点的父节点(.和..只能作用元素节点,属性和文本不行,//@id/..并未选取到具有id属性元素的父元素) //@id # 具有id属性的元素(//@id='kw'也不成立,//后只能跟元素名称,而不能进行筛选,筛选使用谓语) //input[@name="wd"] # name属性等于wd的input元素 //a[text()='意见反馈'] # 文本属性等于"意见反馈"的a元素 //input[@type="hidden" and @name="f"] # and运算符,双属性匹配 //input[@type="hidden" and @name="f"] | //input[@id='kw'] # 选取两个元素 //form[@id="form"]/* # id=form的form标签下任意子元素 //form[@*] # 任意带有属性的form标签
xpath轴
当元素即无唯一属性,使用路径表达式层级特别深时,还可以使用xpath轴定位。利用元素之间的关系,模糊定位,减少对层级的依赖
轴可定义相对于当前节点的节点集**,路径表达式/节点关系****::节点挑选**
节点关系 释义 轴名称
父节点(parent) 除根节点外,每个元素都有一个父节点 parent:当前节点的父节点
子节点(children) 元素可以拥有零个;一个或多个子节点 child:当前节点的所有子元素
同胞节点(sibling) 拥有同一个父节点的节点
先辈节点(ancestor) 父节点,父节点的父节点,都称为先辈节点 ancestor:当前节点的所有先辈(父、祖父等)
后代节点(descendant) 子节点,子节点的子节点,都称为后代节点 descendant:当前节点的所有后代元素(子、孙等)
preceding 当前节点开始前的节点 preceding-sibling:当前节点前的所有同级节点
following 当前节点结束后的节点。
self 选取当前节点。 descendant-or-self:当前节点的所有后代元素(子、孙等)以及当前节点本身
//form/div[last()-1]/ancestor::div[@class='modal-content']
w3schoolxpath介绍:https://www.w3school.com.cn/xpath/xpath_syntax.asp
testerhomexpath总结:https://testerhome.com/topics/20296
CSS_SELECTOR定位
css_selector定位是另一种可选的方式
在项目中推荐优先选择css,
css是配合html使用,通过匹配对象的原理定位元素,而xpath是配合xml工作的,通过遍历文档节点匹配元素,css性能更优秀
语言简洁,明了,相对xpath
原因3:前段开发主要是使用css,不使用xpath,所以在技术上面,我们可以获得帮助的机会非常多
题外话:据说xpath和css现在基本没有什么太大的区别了,css已经实现了大多数的xpath功能,只有个别功能没有实现。具体的数据列证还需要找更多的数据进行填充。
chrome-console验证: 或 者 $(“css_selector”)
选择器 示例 释义 备注
属性定位 element $('input') 标签名称为input的元素
#id $('#kw') id="kw" 的元素
.class $('.s_ipt') class="s_ipt" 的元素
[attribute] $('[type]') 选择带有type属性的元素
[attribute=value] $('[name="wd"]') name=wd的元素
[attribute~=value] $('[class~="tang-pass-login"]') class属性值包含tang-pass-login的元素 可用于完整属性值匹配,或者由空格分隔的属性值部分匹配
[attribute|=value] $('[class|="pass"]') class属性以pass开头的元素 该值必须是整个单词,比如 lang="en",或者后面跟着连字符,比如 lang="en-us"。
[attribute^=value] $('[class^="pa"]') class属性值以pa开头的元素 这两个方法,可以匹配属性值中的部分字符进行匹配
[attribute$=value] ="go"]') class属性以go结尾的元素
层级定位 e1>e2 $('span>input') 父元素为span的input名称子元素 >操作元素为父子关系,非后代
e1,e2 $('a,div') 所有a和div元素
e1 e2 $('a div') a元素内部的所有div元素 内部:div是a的后代元素
e1+e2 $('div+a') 紧接在div之后的a元素 紧接:div和a是同胞关系
e1:nth-child(n) $('span>span:nth-child(1)') span父元素下,第一个span名称的子元素 nth-child作用于筛选父元素下特定名称,指定位置的子元素
find_element_by_css_selector("input#kw") # input标签和id属性组合定位 find_element_by_css_selector("input.s_ipt") # input标签和class属性定位 find_element_by_css_selector('a[src$=".pdf"]') # src元素以pdf结尾的a元素 find_element_by_css_selector("[name='wd'][autocomplete='off']") # 两个属性组合定位