全栈测试开发系列----Selenium元素定位大全

 目录:

一、webdriver基本定位方式

二、父子定位、二次定位

三、JS定位

四、jQuery定位

 

  元素定位是整个Web自动化中的重点和难点。Selenium实现网页的控制操作主要是通过控制前段的元素来完成的。在这个过程中,元素定位是基础,只有准确的抓取到对应的元素才能进行后续的自动化控制操作。

  Selenium Python提供了一种用于定位元素(Locate Elements)的策略,你可以根据所爬取网页的HTML结构选择最适合的方案。定位多个元素时,只需将方法“element”后加s,这些元素将会以列表的形式返回。

定位单个元素的方法 定位多个元素的方法 方法含义

find_element_by_id

find_elements_by_id 通过标签id属性定位元素
find_element_by_name find_elements_by_name 通过标签name属性定位元素
find_element_by_xpath find_elements_by_xpath 通过xpath路径定位元素
find_element_by_link_text find_elements_by_link_text 通过显示文本定位元素
find_element_by_partial_link_text find_elements_by_partial_link_text 通过超链接文本定位元素
find_element_by_tag_name find_elements_by_tag_name 通过标签名定位元素
find_element_by_class_name find_elements_by_class_name 通过类名定位元素
find_element_by_css_selector find_elements_by_css_selector 通过CSS选择器定位元素

 重点注意:

# 这里selenium最新版已经弃用了find_element_by_*方法,如果继续使用这些方法,selenium需要降低版本,否则会报错

# 报错信息:AttributeError: 'WebDriver' object has no attribute 'find_element_by_*'

使用最新的版本的替换方式: find_element()

使用的时候需要导入模块    from selenium.webdriver.common.by import By

属性定位方法 原定位方法find_element_by_* 推荐定位方法find_element()
id find_element_by_id find_element(By.ID,"element_id")
name find_element_by_name find_element(By.NAME,"element_name")
xpath find_element_by_xpath find_element(By.XPATH,"//标签名[@属性名='属性值']")
link_text find_element_by_link_text find_element(By.LINK_TEXT,"element_link_text")
partial_link_text find_element_by_partial_link_text find_element(By.PARTIAL_LINK_TEXT,"element_partial_link_text")
tag_name find_element_by_tag_name find_element(BY.TAG_NAME,"element_tag_name")
class_name find_element_by_class_name find_element(By.CLASS_NAME, "element_class_name")
css_selector find_element_by_css_selector find_element(By.CSS_SELECTOR, "element_css_selector")

 

 

DSMALL商城登录页面演示

 

一、webdriver基本定位方式

 

1、id定位

  该方法是通过网页标签的id属性定位元素,它将返回第一个用id属性值匹配定位的元素。如果没有元素匹配id值,将会返回一个NoSuchElementException异常。 

from selenium import webdriver
import time

driver = webdriver.Chrome()
driver.get('http://192.168.235.128/index.php/home/login/login.html')
# 窗口最大化
driver.maximize_window()
time.sleep(2)
assert "德尚商城" in driver.title
print(driver.title)

# 定位id为member_name的元素,并输入账号,截屏
driver.find_element_by_id("member_name").send_keys('test')
time.sleep(2)
driver.save_screenshot('inputname.png')

driver.close()
driver.quit()

 修改代码后可以使用:

from selenium.webdriver.common.by import By

driver.find_element(By.ID,"member_name").send_keys('test')

 

2、name定位

  该方法是通过网页标签的name属性定位元素,它将返回第一个用name属性值匹配定位的元素。如果没有元素匹配name值,会返回NoSuchElementException异常。

driver.find_element_by_name("member_name").send_keys('test')


driver.find_element(By.NAME, "member_name").send_keys('test')

 

3、XPath定位  

  XPath定位方式由XML(eXtendMarkup Language,可扩展标记语言,也是由一系列标签构成,主要实现数据交换)和 Path 两部分构成,以XML 格式的树状结构形式进行递归逐级定位。
  XPath 定位的两种方式:绝对路径定位相对路径定位
  绝对路径:从顶级父标签到当前标签的整个路径结构称为绝对路径。在使用绝对路径时,如果同级中存在多个相同标签,则通过索引进行具体选择,其索引的初始值是从1开始!但是在实际脚本开发过程中,一般不使用绝对路径,因为绝对路径的跨度较大,只要页面稍微发生变动整个定位就会失败,稳定性极差。
  相对路径:表示相对当前标签而言的路径结构。常用的定位方式有以下几种。

    (1)属性定位语法://标签名[@属性名=属性值]。

注意

(1)标签名可以具体,也可以使用* (表示任意标签,定义的范围会比具体的标签更广,可能会定位出多个对象)。

(2)属性值如果是字符串则需要使用引号。

    (2)使用逻辑运算符可以实现多个属性定位,逻辑运算符有 and、or、not。例如,/inputl@name=uname and@pwd=upasswd7,但是一般组合的属性不会超过2个,因为设定属性越多,对脚本的依赖性就越高。
    (3)嵌入函数完成XPath 定位。
      text函数定位语法://标签名[text()=对应标签的文本内容]
      contains函数定位语法://标签名[contains(@属性名,对应属性名的部分值)]。

      starts-with 函数定位语法://标签名[starts-with(@属性名,对应属性名的前面部分值)]

      ends-with 函数定位语法: //标签名[ends-with(@属性名,对应属性名的后面部分值)]

注意

一般 starts-with、ends-with 函数能完成定位的,contains 函数也能完成,所以在实际工作中 contains函数应用得更多。

实例代码如下。

driver.find_element_by_xpath("//button[text()=登录]").click()

driver.find_element_by xpath("//button[contains(@class,login')]").click()

driver.find_element_by xpath("//button[starts-with(text(),登')]").click()

  XPath是用于定位XML文档中节点的技术,HTML\XML都采用网页DOM树状标签的结构进行编写的,所以可以通过XPath方法分析其节点信息。Selenium Python也提供了类似的方法来跟踪网页中的元素。

  XPath定位元素方法不同于按照ID或Name属性的定位方法,前者更加的灵活、方便。 

  比如想通过ID属性定位超链接信息,但是ID属性值都是相同,即“link”,如果没有其他属性,那我们怎么实现呢?此时可以借助XPath方法进行定位元素。这也体现了XPath方法的一个优点:

    当没有一个合适的ID或Name属性来定位所要查找的元素时,你可以使用XPath去定位这个绝对元素(但作者不建议定位绝对元素),或者定位一个有ID或Name属性的相对元素位置。

driver.find_element(By.XPATH, "//*[@id='member_name']").send_keys('test')

 

4、链接文本定位超链接:link_text、partial_link_text

  当需要定位一个锚点标签内的链接文本(Link Text)时就可以使用该方法。该方法将返回第一个匹配这个链接文本值的元素。如果没有元素匹配这个链接文本,将抛出一个NoSuchElementException异常。

 

代码示例:

driver.find_element_by_link_text("忘记密码?").click()
driver.find_element_by_partial_link_text("忘记").click()

driver.find_element(By.LINK_TEXT,"忘记密码?").click() driver.find_element(By.PARTIAL_LINK_TEXT,"忘记").click()
partial_link_text是link_text的一种补充,有些文本链接较长时,可以截取一部分进行定位,只要这一部分信息可以唯一的识别出这个链接。

 5、tag_name定位

  该方法是通过标签名(Tag Name)定位元素,它将返回第一个用Tag Name匹配定位的元素。如果没有元素匹配,将会返回一个NoSuchElementException异常。

    用这种定位方法定位通常比较困难,因为同一个页面中相同名称的标签往往比较多。

driver.find_elements_by_tag_name('input')

# 获取多个标签之后,通过下标索引获取目标进行操作
driver.find_elements(By.TAG_NAME,"input")[0].send_keys('test')

 

6、class_name定位

  该方法是通过类属性名(Class Attribute Name)定位元素,它将返回第一个用类属性名匹配定位的元素。如果没有元素匹配,将会返回一个NoSuchElementException异常。

    用这种定位方法定位通常比较困难,因为同一个页面中相同类名的属性也会比较多。

 

  此处,登录按钮的类名属性应该的是只有一个,可以复制并通过:Ctrl+F搜索该名称看一下

 

代码示例

driver.find_element_by_class_name("btn login-btn")


driver.find_element(By.CLASS_NAME,"btn login-btn")

 

7、css_selector定位

  该方法是通过CSS选择器(CSS Selectors)定位元素,它将返回第一个与CSS选择器匹配的元素。如果没有元素匹配,将会返回一个NoSuchElementException异常。

  CSS定位和XPath定位的使用是同等重要的,两者又很多类似的地方,但是无论从性能还是语法上,CSS定位更具优势。CSS选择器定位方法是比较难的一个方法,详细的CSS选择器参考手册:https://www.w3school.com.cn/cssref/css_selectors.asp

# 忘记密码
driver.find_element(By.CSS_SELECTOR,"#login_normal_form > div:nth-child(4) > a:nth-child(1)").click()

# 输入用户名
driver.find_element(By.CSS_SELECTOR,"#member_name").click()

 

 

 

二、父子定位、二次定位

  父子定位:如果当前标签或者子标签中不存在任何属性可以作为定位方式,则可以查找当前标签的父标签,是否存在可以定位的属性,如果父级还没有,则可以继续往上一级查找,以此类推,直到查找到可以定位的标签。

  二次定位:可以先定位到可以定位的其中一级标签获取对象,然后再通过该对象作为基准再次定位(二次定位实际就是实现多个节点的划分,通过节点进一步明确定位的标签和元素)

 

  当前级中如果没有属性可以定位,则可以寻找上一级父标签进行定位,然后再接子标签;注意父标签的属性是否于其他的标签相同。

  # 多观察当前标签周围的标签的属性。

 

三、JS定位

  除此之外,还有一些是使用基础定位方式无法解决的问题,比如Windows窗口、浏览器滚动条等,这时需要使用到JS定位。

  JS实际上是使用了DOM树的定位方式

  DOM树表示树形展示的层级结构,层级结构很好的体现了元素与元素之间的联系。

  常用的几种定位方式如下: 

    1. id定位:document.getElementsById()
    2. name定位:document.getElementsByName()
    3. tag定位:document.getElementsByTagName()
    4. class定位:document.getElementsByClassName()
    5. CSS定位:document.querySelectorAll()

以上方法属于document对象的方法,document表示当前HTML页面的对象,具体的API可以参考:https://developer.mozilla.org/zh-CN/docs/Web/API

 

注意:

1、在使用以上方式进行定位的时候,name、tag、class、CSS定位返回的对象都是复数形式,所以需要索引获取其具体的对象。

2、文本赋值使用的是该方法的value属性,如果是按钮则直接使用click()方法

3、如果已通过定位元素获取了对应的对象,但是该对象无法直接完成某些事件的操作,则可以通过该对象调用该标签的中声明的操作事件的属性值(使用JS脚本完成),然后直接使用execute_script执行

 

代码示例(注意这里的单复数形式)

username_js = "document.getElementById('member_name').value='test';"
password_js = "document.getElementById('member_password').value='123456';"
driver.execute_script(username_js)
driver.execute_script(password_js)

username_js2 = "document.getElementsByName('member_name')[0].value='test';"
password_js2 = "document.getElementsById('member_password')[0].value='123456';"
driver.execute_script(username_js2)
driver.execute_script(password_js2)

 

可以在浏览器控制台验证

 

四、jQuery定位

  有些开发人员开发的系统中,前面的定位方式都不适用,都无法定位出来,此时需要使用jQuerry定位,然后使用键盘操作

  常用jQuery定位方法有两种:

    使用jQuery选择器来完成元素的选择操作,可以直接获取一个或者一组元素;

    通过jQuery遍历来选择元素,这种方式常用在获取层级较为复杂的页面元素的情况。

  选择器参考手册:https:www.w3school.com.cn/jqurey/jquery_ref_selectors.asp

jQuery语法实际上是为了HTML元素的选择设置的,不仅可以完成定位,还可以直接堆元素完成一些具体的操作,基础语法:$(selector).action()

通过$符号进行定义,selector选择器主要用于获取具体的HTML元素,而action()用于实现堆获取的元素具体的操作。

常用操作:

$(selector).val('input_value')
input_value表示要输入的文本


$(selector).val('')
如果为空,则执行后是清空的意思。

$(selector).click()
表示单击操作

 

登录框示例代码:

 

# 定位用户名
username_jq = "$('input:first').val('test')"
driver.execute_script(username_jq)


# 定位登录按钮
login_jq = "$('.btn login-btn').click()"
driver.execute_script(login_jq)


# 获取对应标签的文本信息
text_jq = "return $('#属性名').text();"
print(driver.execute_script(text_jq))


# 引用CSS样式中的表示形式,获取属性href值
get_herf_script = "return $('#login_normal_form > div:nth-child(4) > a:nth-child(1)').attr('herf')"
print(driver.execute_script(get_herf_script))

 

jQuery常用方法总结:

4.1、核心方法

  $('element').length:元素的个数,length是属性

  $('element').size():元素的个数,size()是方法

  $('element').get():获取元素在页面中的集合,以数组的形式存储

  $('element').get(index):功能和上面相同,index表示第几个元素,是数组的下标。

  $('element').get().reverse():将得到的数组逆序排列

  $('element1').index($('element2')):获取元素2在元素1中的索引值

 

4.2、基本对象获取

注意:这里获取的都是jQuery对象而不是DOM对象,但是可以互相转换

  $("*"):表示获取所有对象,不常用

  $("#xxxx"):获得id=xxxx的元素对象(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元素

 

4.3、层级元素获取

  $("element1 element2 element3 ..."):前面是父级,后面是子集

  $("div > p"):获取div元素后面的直接后代p元素

  $("div + p"):获取div元素后面的第一个p元素

  $("div ~ p"):获取div元素之后所有同层级的p元素

 

4.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)"):匹配所有小于给定索引值的元素

 

4.5、内容对象的获取和对象可见性

  $("element:contains(text)"):获得包含text的元素

  $("element:empty"):获得不包含子元素或文本的元素

  $("element:partnt"):获得包含子元素或文本的元素

  $("element:has(selector)"):获得包含某个元素的元素,如$("p:has(span)")表示所有包含span元素的p元素

  $("element:hidden"):选择所有不可见元素

  $("element:visible"):选择所有可见元素

 

4.6、其他对象获取方式

  $("element[id]"):获取所有带有id属性的元素

  $("element[attribute = youlike]"):获得所有attribute属性为youlike的元素

  $("element[attribute != youlike]"):获得所有attribute属性不是youlike的元素  

  $("element[attribute ^= youlike]"):获得所有attribute属性不是以youlike开头的元素

  $("element[attribute $= youlike]"):获得所有attribute属性不是以youlike结尾的元素

  $("element[attribute *= youlike]"):获得所有attribute属性包含youlike的元素

  $("element[selector1][selector2][...]"):复合属性选择器。例如,$("input[id][name][value=youlike]")表示获得带有id、name属性且value属性是youlike的input元素

 

4.7、子元素的获取

  $("element:nth-child(index)"):选择父级下面的第N个元素

  $("element:nth-child(even)"):选择父级下面的偶数

  $("element:nth-child(odd)"):选择父级下面的奇数

  $("element:nth-child(3n+)"):执行表达式

  $("element:first-child"):选择父级下面的第一个子元素

  $("element:last-child"):选择父级下面的最后一个子元素

  $("element:only-child"):选择父级下面的唯一一个子元素,例如,dt在dl列表中唯一,那么将选择dt

 

4.8、表单对象获取

  $(:input):查找所有的input元素,包括下拉列表、文本域、单选框、复选框等

  $(:text):匹配所有的单行文本框

  $(:password):匹配所有的密码框

  $(:radio):匹配所有的单选按钮

  $(:checkbox):匹配所有的复选按钮

  $(:submit):匹配所有的提交按钮

  $(:image):匹配所有的图像域

  $(:reset):匹配所有的重置按钮

  $(:button):匹配所有的按钮

  $(:file):匹配所有的文件上传域

  $(:hidden):匹配所有的不可见元素或者type为hidden的元素

  $(:enabled):匹配所有可用的input元素。例如,radio:enabled表示匹配所有可用的单选按钮

  $(:disabled):匹配所有的不可用input元素,作用与上相反

  $(:checked):匹配所有选中的复选框元素

  $(:selected):匹配所有下拉列表

 

4.9、元素属性的设置与移除

  $("element").attr(name):取得第一个匹配的属性值,例如$("img").attr("src")

  $("element".attr(key,value)):为某一个元素设置属性

  $("element".attr({key:value,key1:value,...})):为某一个元素一次性设置多个属性

  $("element").attr(key,function):为某一个元素设置一个计算的属性值

  $("element").removeAttr(name):为某一个元素移除name属性

 

 

 

思考:隐藏元素如何操作?  

 

  隐藏元素是可以定位的,其定位方式与普通元素的定位方式完全一样,只是隐藏元素无法进行操作。

  可以通过JS脚本定位到该元素,获取对应的元素对象,然后通过removeAttribute和setAttribute两个方法完成属性的删除或者重新赋值操作,使当前的属性处于显示状态,即可完成操作。

 

posted @ 2023-06-20 01:45  C_N_Candy  阅读(110)  评论(0编辑  收藏  举报