1. 元素定位的重要性
无论是做自动化测试,还是爬虫,页面元素定位 永远都是第一步,在没有定位到网页元素之前,任何自动化操作都没法进行。
Selenium WebDriver API 中提供了大量的方法帮助我们进行元素定位。
2. 常用方式
Selenium 常用的元素定位方式包含:id、name、class。
前端工程师在编写 Web网站的时候,大部分的网页标签都会包含 id、name、class 中的其中一个或者多个。
其中,一个页面内的 id 一般具有唯一性,也是使用最多的一种元素定位方式;name、class 分别对应网页标签的name 属性、class 属性。
打开目标网页,按 F12 键打开开发者调试工具,定位到元素标签,如果存在 id 、name、class 属性,就可以使用 id 、name、class 中的其中一个来定位到元素,
具体的使用方法如下:
# 使用 id 定位
driver.find_element_by_id("element_id")
# 使用 name 定位
driver.find_element_by_name("element_name")
# 使用 class 定位
driver.find_element_by_class_name("element_class")
3. Xpath
Xpath在 XML 文档中本身是一种元素定位语言,而 HTML 是 XML 是另外一种实现,在元素定位的时候会遍历页面的所有元素,所以查询效率不高。
Selenium 中 Xpath 定位方式包含:绝对路径定位、属性定位、元素关系定位、运算符、匹配等。
绝对路径定位:相当于从最顶部的 html 元素标签往子标签追加,一直定位到目标元素标签,这种方式不常用。
driver.find_element_by_xpath('/html/body/div/.../div/目标元素')
实际上在做 App 端自动化 的时候,Appium / Airtest 元素定位的时候,某些元素没有任何属性和可用的层级关系定位方式,这时候借助绝对定位是唯一的选择。
属性定位:对应网页元素标签的任意属性,只要能唯一标识目标元素即可。
属性定位很简单,可以显式的指定目标元素的标签名或用 * 号匹配任意标签名,使用格式是:’//元素标签[@属性名=“属性值”]’
# 1、通过标签名来定位
driver.find_element_by_xpath('//div[@id="element_id"]')
# 2、也可以用*号代替
driver.find_element_by_xpath('//*[@name="element_name"]')
元素关系定位:当一个元素标签没有任何属性值,但是父元素标签存在唯一的属性值,这时候可以先找到父元素标签,然后再找到自己。
# 通过父元素标签找到自己
# 父元素标签含有属性值 class = parent_class
# 子元素标签为a
driver.find_element_by_xpath('//div[@class="parent_class"]/a")
运算符定位:页面可能多个元素包含同一个属性,这时候可以使用逻辑元素符 and 连接多个属性来定位元素标签。
# 通过多个属性值来唯一定位元素标签
driver.find_element_by_xpath('//div[@属性1="属性1的值" and @属性2="属性2的值"]')
匹配定位:匹配定位平常使用不多,主要是利用属性中包含某个字符串来定位元素标签,包含:contains、starts_with
# 匹配定位
# class属性值中包含:class
driver.find_element_by_xpath('//div[contains(@class,"part_str")]')
# class属性值以part_start开头
//input[starts-with(@class,'part_start')]
实际上,网页元素标签的 Xpath 表达式可以使用 Chrome 右键属性或者 Xpath Chrome 插件去快速获取。
4. CSS Selector
CSS Selector 是利用 CSS 选择器来定位元素,相比 Xpath,语法更简洁,元素定位速度更快一点。
常见的选择器包含:class、id 两种,使用方式如下:
# 利用元素class来定位
driver.find_element_by_css_selector(".element_class")
# 利用元素id来定位
driver.find_element_by_css_selector("#element_id")
和 Xpath 一样,CSS Selector 元素没有任何可用的属性值时,可以使用 层级关系先定位 到父元素标签,然后再找到自己。
# 利用元素层级关系进行定位
driver.find_element_by_css_selector("parent_div > target_element_div")
属性定位:在 CSS Selector 中也很常见,使用方式如下:
# 属性定位
driver.find_element_by_css_selector('[属性名=属性值]')
需要注意的是,属性定位必须确保在当前页面内,这个属性具有唯一性。
组合定位:将上面的定位方式结合在一起,即可以加强元素的唯一性,精准快速地定位到元素标签。
# 组合定位
# 父元素:parent_div,class = parent_class
# 目标元素:targent_div,id = targent_id
driver.find_element_by_css_selector("parent_div.parent_class > targent_div#targent_id")
5. 不常用方式
上面的元素定位方式都很常用,下面这些定位方式几乎用不到,包含:
Tag 定位:利用 Tag 标签名去定位,一般网页中都会包含多个 Tag,所以利用 Tag 去元素定位不实用。
# Tag定位,比如:tag为input
element_by_input_tag = driver.find_element_by_tag_name("input")
link 定位:link 定位是针对 a 标签中的文本匹配。
由于很多网页元素都是动态变化的,文本匹配经常需要修改,所以灵活性不高,很少使用。
# 比如:
# <a href="http://www.baidu.com">百度一下</a>
# 使用link来定位
driver.find_element_by_link_text("百度一下")
partial link 定位:相比 link 定位,相当于 a 标签内容局部匹配,只要包含待匹配的内容,即使要查找的元素。
# 比如:
# <a href="http://www.baidu.com">百度一下</a>
# 使用 partial link 来定位来定位
driver.find_element_by_link_text("百度")
6. By + elements
Selenium 提供的查找方法还提供了另外一种形式,即通过:By( 定位方式,定位内容值 )
实际上,对自动化做 Page Object 设计 的时候,一般都会用 By 的方式来封装代码,更易于我们维护代码。
使用方式如下:
# 1、导入依赖类
from selenium.webdriver.common.by import By
# 2、使用
driver.find_element(By.ID, "element_id")
driver.find_element(By.NAME, "element_name")
driver.find_element(By.CLASS_NAME, "element_class_name")
driver.find_element(By.TAG_NAME, "element_tag_name")
driver.find_element(By.LINK_TEXT, "element_link_text")
driver.find_element(By.PARTIAL_LINK_TEXT, "element_partial_link_text")
driver.find_element(By.XPATH, "//*[@class='element_xpath']")
driver.find_element(By.CSS_SELECTOR, "element_css_selector")
上面查找元素的方法都是针对单个元素标签,如果要查找匹配多个元素,只需要将 element 改成 elements 即可。
# 单个元素
driver.find_element(By.ID, "element_id")
# 多个元素
driver.find_elements(By.ID, "element_id")
Selenium 元素定位的内容差不多就这些了,下一篇将聊聊 Selenium 具体应用场景的使用方式。