前言
web自动化中最核心最难的部分就是元素的定位,Selenium对网页的控制是基于各种前端元素
Id定位
- 这是一种最常用的定位方式,假设已知某个元素的id或通过Firebug查找得到id的相关信息,可通过此方法进行定位,如下图:id属性是html中是唯一的,类似于元素的身份证号码,webdriver提供的id定位方法就是通过元素的id属性来查找元素driver.find_element_by_id(“kw”)找到元素所在标签的id属性值
Name定位
- name定位方式将会识别首个name属性等于定位值的页面元素。如果有多个元素的name属性都相同,那么可以使用过滤器来进一步细化定位。默认的过滤器类型是value(也就是value属性)
- 实例代码:driver.find_element_by_name(“tj_trnews”)
Class_Name定位
- html规定class来指定元素的类型,class属性在页面中不是唯一的
- 实例代码:driver.find_element_by_class_name("bri")通过class属性来定位元素的位置
Tag_Name定位
- driver.find_elements_by_tag_name("input")
- 通过标签的名称来定位元素的位置,这种定位方法比较困难,因为同一个页面中,相同名称的标签往往比较多
Link_Text定位
- link_text专门用来定位文本链接
- driver.find_element_by_link_text("新闻")
- 使用a标签中链接的文字内容来定位页面上的具体元素
Partial_Link_Text定位
- partial_link_text是link_text的一种补充,有些文本链接较长的时候,可以取文本链接的一部分进行定位,只要这一部分信息可以唯一的标识出这个链接
driver.find_element_by_partial_link_text(“-腾讯视频")
Xpath定位
- xpath定位方式:表示的由xml(extend markup language 可扩展标记语言,也是由一系列标签所构成,主要是实现数据交换(用于做配置文件))+path,以xml格式的树状结构形式进行递归逐级定位;
- xpath的定位两种方式:绝对路径定位、相对路径定位;
绝对路径:从顶级父标签到当前标签的整个结构过程称之为绝对路径;
在使用绝对路径时,如果同级中存在多个相同标签的话,则通过索引进行具体选择(其索引的初始值是从1开始);但是在实际脚本开发过程中,一般不用,因为如果使用绝对路径则跨度较大,只需要页面稍微修改结构则整个定位失败;(稳定性极差)
相对路径:表示的是相对当前标签而言;
- i.属性定位语法://标签名[@属性名=属性值]
注意:1.标签名可以具体,也可以使用* (表示的任意标签,定义的范围会比具体的标签更广,可能定位出多个对象) 2.属性值如果是字符串的话则需要使用引号; - ii.使用逻辑运算符进行实现多个属性定位:and or not例如://input[@name='uname' and @]但是一般组合的属性不会超过2个,因为设定属性过多其脚本的依赖性越高;
- iii.嵌入函数完成xpath定位:
a.文本函数定位://标签名[text()=对应标签的文本内容]文本内容中 是否嵌入标签、文本内容表示的完整文本;
b.包含函数定位://标签名[contains(@属性名,对应属性名的部分值)]
c.以指定字符开头定位://标签名[starts-with(@属性名,对应属性名 的前面部分值)]
d.以指定字符结尾定位://标签名[ends-with(@属性名,对应属性名 的后面部分值)]
说明:一般starts-with、ends-with都可以使用contains完成;
示例
# get_dri.find_element_by_xpath("//button[text()='登 录']").click()
# get_dri.find_element_by_xpath("//button[contains(@class,'login')]").click()
# get_dri.find_element_by_xpath("//button[starts-with(text(),'登')]").click()
Css定位方式
- css表示的是层叠式样式;css定位方式要比xpath定位方式效率更高;
- a.id定位表示方式:#id值
- b.class定位表示方式:.class的值
- c. element1> element2(element1 element2):表示的是指定element1下面的所有element2元素nth-child(n) 表示指定父元素的第几个子元素、last-child:表示的是指定父元素的最后一个子元素、first-child:表示的是指定父元素的第一个子元素
详细的css选择器语法参考手册:
https://www.w3school.com.cn/cssref/css_selectors.asp
示例
#print(get_dri1.find_element_by_css_selector("div>h3>a"))
#print(get_dri1.find_elements_by_css_selector('[id="3"]'))
get_dri1.find_element_by_css_selector('div[id="3"]>h3>a').click()
elements复数定位
在上面的例举的八中基本定位方式种,都有对应的复数形式,分别是下面这些:
- id复数定位find_elements_by_id()
- name复数定位find_elements_by_name()
- class复数定位find_elements_by_class_name()
- tag复数定位find_elements_by_tag_name()
- link复数定位find_elements_by_link_text()
- partial_link复数定位find_elements_by_partial_link_text()
- xpath复数定位find_elements_by_xpath()
- css复数定位find_elements_by_css_selector()
这些复数定位方式每次取到的都是具有相同类型属性的一组元素,所以返回的是一个list队列,我们也可以利用这个去定位单个的元素。比如百度首页种,右上角有新闻、视频、地图、贴吧等一些链接,我们通过f12查看源码可以发现,这些链接都有共同的class 。
举个例子,比如定位排在第六个的学术,可以这样定位:
driver.find_elements_by_class_name("mnav")[5].click()
还可以通过css的复数定位写法:
driver.find_elements("css selector",".mnav")[6].click()
当然,也可以借助pop()函数,一般pop()或pop(-1)表示获取元素种的最后一个,pop(2)表示第三个:
driver.find_elements("css selector",".mnav").pop().click()
By定位
通过对上面8种基本元素定位方式的学习,在使用过程种可以根据实际的情况去选择对应的的定位方式,我们可以用By来设置定位策略;
具体语法如下:
- find_element(By.ID,"kw")
- find_element(By.NAME,"wd")
- find_element(By.CLASS_NAME,"s_ipt")
- find_element(By.TAG_NAME,"input")
- find_element(By.LINK_TEXT,u"新闻")
- find_element(By.PARTIAL_LINK_TEXT,u"新")
- find_element(By.XPATH,"//button[text()='登 录']")
- find_element(By.CSS_SELECTOR,"div[id="3"]>h3>a")
上面这些使用的前提是需要导入By类:from selenium.webdriver.common.by import By
高级定位方式
父子定位、二次定位
- 父子定位:如果当前标签或者子级标签中不存在任何属性可以作为定位的方式时,则可以查找当前标签的父标签是否存在相应可定位的属性,如果父级还没有则可以查找再上一级,以此类推,直到查找到可定位的标签为止;
- 二次定位:可以先定位到可定位的其中一级标签获取对象,然后再通过该对象进行作为基准再次定位(二次定位实际就是实现多个节点的划分,通过节点进行进一步明确定位的标签和元素)
#get_dri1.find_element_by_xpath("//h3[contains(@class,'c-gap-bottom-small')]").find_element_by_xpath("//a").click()
#当前级中如果没有属性可以定位,则可以寻找上一级父标签进行定位,然后再接子标签;注意父标签的属性是否与其他标签相同
#多观察当前标签的周围标签属性
#get_dri1.find_element_by_xpath("//div[@id=3]/h3/a").click()
JS定位
- id定位:document.getElementById()
- name定位:document.getElementsByName()
- tag定位:document.getElementsByTagName()
- class定位:document.getElementsByClassName()
- css定位:document.querySelectorAll()
以上方法都属于document对象的方法;document表示的是实际就是当前html页面的对象,且具体的api可参考:https://developer.mozilla.org/zh-CN/docs/Web/API
- 注意:1.在使用以上方式进行定位时,注意Name、ClassName、TagName、QuerySelectorAll返回的对象都是复数形式;所以需要通过索引进行获取其具体对象;2.针对文本赋值的是该方法调用value属性,如果是按钮的话则直接使用click()方法;
- 2.通过定位元素获取对应的对象,但是该对象无法直接完成某些事件的操作,则可以通过该对象调用该标签中所声明的操作事件的属性值(js脚本完成),则获取该属性后可直接使用execute_script进行执行即可;
示例
username_js = "document.getElementsByName('username')[0].value='wood';"
username_js2 = "document.getElementsByTagName('input')[0].value='wood';"
button_js = "document.getElementById('findpwd').click();"
button_js2 = "document.getElementsByClassName('logindo')[0].click()"
driver.execute_script(username_js2)
driver.execute_script(button_js2)
jQuery定位元素的方法有两种,一种是通过jQuery 选择器来选择元素,可以直接获取单个或批量的元素;另一种是通过jQuery 遍历相关来选择元素,这种方法常用在获取层级较复杂的页面中的元素。
jQuery 选择器参考手册地址:
https://www.w3school.com.cn/jquery/jquery_ref_selectors.asp
jQuery语法是为HTML元素的选取编制的,可以对元素执行一些具体的操作
基础语法是
$(selector).action()
$符号定义jQuery,selector选择器用来查询具体的HTML元素,通过action()来执行对元素的具体操作。
常用操作:
$(selector).val('input_value') 其中input_value表示要输入的文本的值
$(selector).val('') 如果为空,则执行后是清空的意思
$(selector).click() 表示点击操作
例如:
#定位用户名
query_username="$('input:first').val('admin')"
get_dri.execute_script(query_username)
#定位登陆按钮
query_js="$('.logindo').click()"
get_dri.execute_script(query_js)
#获取对应标签的文本信息
query_text=" return $('#findpwd').text();"
print(get_dri.execute_script(query_text))
#如直接可以引用css样式中的表示形式,获取属性href的值
get_scrip="""return $('div[id="3"]>h3>a').attr("href")"""
print(get_dri1.execute_script(get_scrip))
附录:Jquery常用方法
1.核心方法
$("Element").length; ‘元素的个数,是个属性
$("Element").size(); '也是元素的个数,不过带括号是个方法
$("Element").get(); ‘某个元素在页面中的集合,以数组的形式存储
$("Element").get(index); '功能和上面的相同,index表示第几个元素,数组的下标
$("Element").get().reverse(); ‘把得到的数组方向
$("Element1").index($("Element2")); '元素2在元素1中的索引值是。
2、基本对象获取(注意这里获取的都是Jquery对象而不是Dom对象哦,但是他俩是可以转换滴)
$("*") ‘表示获取所有对象 但是我至今没这样用过
$("#XXX") '获得 id=XXX 的元素对象(id可以是标签的id或CSS样式id) 常用
$("input[name='username']") 获得input标签中name='userName'的元素对象 常用
$(".abc") ' 获得样式class的名字是.abc的元素对象 常用
$("div") ' 标签选择器 选择所有的div元素 常用
$("#a,.b,span") '表示获得ID是a的元素和使用了类样式b的元素以及所有的span元素
$("#a .b p") 'ID号是a的并且使用了 b样式的 所有的p元素
3、层级元素获取
$("Element1 Element2 Element3 ....") '前面父级 后面是子集
$("div > p") '获取div下面的所有的 p元素
$("div + p") 'div元素后面的第一个 p元素
$("div ~ p") 'div后面的所有的 p元素
4、简单对象获取
$("Element:first") 'HTML页面中某类元素的第一个元素
$("Element:last") 'HTML页面中某类元素的最后一个元素
$("Element:not(selector)") '去除所有与给定选择器匹配的元素,如:$("input:not(:checked)") 表示选择所有没有选中的复选框
$("Element:even") '获得偶数行
$("Element:odd“)'获得奇数行
$("Element:eq(index)") '取得一个给定的索引值
$("Element:gt(index)") '取得给定索引值的元素 之后的所有元素
$("Element:lt(index)") '取得给定索引值的元素 之前的所有元素
5、内容对象的获取和对象可见性
$("Element:contains(text)") '元素中是否包含text文本内容
$('Element:empty") '获得元素不包含子元素或文本的
$("Element:partnt") '获得元素包含子元素或文本的
$("Element:has(selector)") ‘是否包含某个元素, 如:$("p:has(span)")表示所有包含span元素的p元素
$("Element:hidden") '选择所有可见元素
$("Element:visible") '选择所有不可见元素
6、其他对象获取方法
$("Element[id]") '所有带有ID属性的元素
$("Element[attribute = youlika ]" '获得所有某个属性为youlika的元素
$("Element[attribute != youlika ]" '获得所有某个属性为不是youlika的元素
$("Element[attribute ^= youlika ]" '获得所有某个属性为不是youlika的开头的元素
$("Element[attribute $= youlika ]" '获得所有某个属性为不是youlika的结尾的元素
$("Element[attribute *= youlika ]" '获得所有某个属性包含youlika的开头的元素
$("Element[selector1][selector2][....]") '符合属性选择器,比如$("input[id][name][value=youlika ]")表示获得带有ID、Name以及value是youlika 的input元素。
7、子元素的获取
$("Element:nth-child(index)") '选择父级下面的第n个元素
$("Element:nth-child(even)") '选择父级下面的偶数
$("Element:nth-child(odd)") '选择父级下面的奇数
$("Element:nth-child(3n+1)") '表达式
$("Element:first-child") '选择父级下面的第一个子元素
$("Element:last-child") '选择父级下面的最后一个子元素
$("Element:only-child") '匹配父级下的唯一的一个子级元素,例如dt在dl列表中唯一,那么将选择dt
8、表单对象获取
$(:input)//查找所有的Input元素,当然也包括下拉列表,文本域,单选框,复选框等。
$(:text)//匹配所有的单行文本框
$(:password)//匹配所有的密码框
$(:radio)//匹配所有的单选按钮
$(:checkbox)//匹配所有的复选框
$(:submit)//匹配所有的提交按钮
$(:image)//匹配所有的图像域,例如
$(:reset)//匹配所有的重置按钮
$(:button)//匹配所有的按钮
$(:file)//匹配所有的文件上传域
$(:hidden)//匹配所有的不可见元素或者type为hidden的元素
$(:enabled)//匹配所有可用的input元素,比如radio:enabled表示匹配所有可用的单选按钮
$(:disabled)//匹配所有的不可用input元素,作用与上相反
$(:checked)//匹配所有选中的复选框元素
$(:selected)//匹配所有的下拉列表
9、元素属性的设置与移除
$("Element").attr(name) '取得第一个匹配的属性值,比如$("img").attr("src")
$("Element".attr(key,value)") '某一个元素设置属性
$("Element".attr({key:value,key1:value,....})) ‘为某个元素一次性设置多个属性
$("Element").attr(key,function) '为所有匹配的元素设置一个计算的属性值。
$("Element").removeAttr(name)//移除某一个属性