3、元素定位详解(上):ID定位、Name定位、Class Name定位、Tag Name定位、Link Text定位
各位同学,咱们今天来聊聊自动化测试里最基础、也最核心的一环——元素定位。
说实话,我刚开始学Selenium的时候,觉得这玩意儿不就是找几个按钮嘛,有啥难的?结果一上手就栽了跟头。脚本跑着跑着就报错,说元素找不到。后来我才明白,定位不准,后面全是白搭。
这一章,咱们先搞定五种最常用的定位方式。它们就像工具箱里的螺丝刀、扳手,你得知道什么时候用哪个。
3.1 ID定位:最快、最稳,没有之一
ID定位,说白了就是元素的身份证号。在HTML规范里,ID应该是唯一的。所以用ID定位,速度最快,也最不容易出错。
我个人习惯是:只要元素有ID,我优先用ID。为什么?因为简单、直接、不绕弯子。
核心要点:ID定位使用 find_element(By.ID, "id值") 方法。
来看个例子。假设页面上有个搜索框,HTML长这样:
<input type="text" id="search-input" placeholder="请输入关键词">
那咱们的Python代码就是:
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://example.com")
# ID定位搜索框
search_box = driver.find_element(By.ID, "search-input")
search_box.send_keys("自动化测试")
你看,三行代码搞定。我在项目中遇到过很多次,开发同学给元素加了动态ID,比如 id="user_12345",这种ID每次刷新都会变。嗯,这时候ID定位就不灵了。所以记住:静态ID用ID,动态ID别用ID。
小技巧:在Chrome浏览器里,右键点击元素 → 检查,就能看到元素的ID。如果ID是纯数字或者带下划线,多半是动态生成的,要小心。
3.2 Name定位:表单元素的标配
Name定位和ID定位很像,只不过用的是 name 属性。在表单提交的场景里,name属性几乎是标配。
你想想看,后端接收表单数据时,靠的就是name字段。所以登录框、注册页这些地方,name属性特别常见。
# Name定位
username = driver.find_element(By.NAME, "username")
password = driver.find_element(By.NAME, "password")
username.send_keys("admin")
password.send_keys("123456")
这里有个坑——name属性不要求唯一。同一个页面里,多个元素可能有相同的name。比如一组单选按钮,name都是 gender。这时候用 find_element 只会找到第一个,想找全部得用 find_elements。
注意:如果页面里有多个同名name元素,find_element 返回第一个,find_elements 返回列表。我曾经因为没注意这个,脚本定位到了错误的元素,排查了半天才发现。
3.3 Class Name定位:样式即定位
Class Name定位,用的是元素的CSS类名。说实话,这个定位方式我用的频率没那么高,因为一个元素往往有多个class,而且class经常被用来控制样式,变化比较频繁。
但有些场景下,它特别好用。比如一组商品卡片,每个卡片都有 class="product-item",你想遍历所有商品,用Class Name定位就很方便。
# Class Name定位
products = driver.find_elements(By.CLASS_NAME, "product-item")
for product in products:
print(product.text)
我记得有一次做电商项目,页面上的商品列表就是用class来区分的。我用 find_elements 一次性拿到了所有商品,然后逐个点击查看详情。嗯,效率确实高。
不过要提醒你:class name如果有空格,说明是多个class的组合。比如 class="btn btn-primary",你不能直接用 "btn btn-primary" 去定位,得用CSS选择器或者只用其中一个class。
避坑指南:Class Name定位只接受单个class名。如果元素有多个class,比如 class="a b c",用 By.CLASS_NAME, "a" 是可以的,但用 By.CLASS_NAME, "a b" 会报错。
3.4 Tag Name定位:最通用的“笨办法”
Tag Name定位,就是通过HTML标签名来找元素。比如 div、span、a、input 这些。
说实话,这个定位方式我平时用得最少。为什么?因为太宽泛了。一个页面上可能有几十个 div,你定位到哪个?
但它也不是一无是处。比如你想统计页面上有多少个链接,或者获取所有输入框,用Tag Name就很快。
# Tag Name定位
all_links = driver.find_elements(By.TAG_NAME, "a")
print(f"页面上共有 {len(all_links)} 个链接")
all_inputs = driver.find_elements(By.TAG_NAME, "input")
print(f"页面上共有 {len(all_inputs)} 个输入框")
我在做页面结构分析的时候,偶尔会用Tag Name来快速了解页面布局。比如检查是不是所有图片都有alt属性,就可以先拿到所有 img 标签,再逐个检查。
使用场景:Tag Name定位适合做批量操作或统计,不适合精确定位单个元素。如果你非要定位单个元素,建议配合索引使用,但说实话,那样代码可读性很差。
3.5 Link Text定位:专治各种超链接
Link Text定位,顾名思义,就是通过链接的文本内容来定位 <a> 标签。这个定位方式有两个变种:Link Text(精确匹配)和 Partial Link Text(部分匹配)。
我个人觉得,这个定位方式在测试导航菜单、面包屑导航、页脚链接时特别好用。因为链接文本通常是人眼可读的,写出来的代码也很直观。
# Link Text定位(精确匹配)
about_link = driver.find_element(By.LINK_TEXT, "关于我们")
about_link.click()
# Partial Link Text定位(部分匹配)
contact_link = driver.find_element(By.PARTIAL_LINK_TEXT, "联系")
contact_link.click()
这里有个细节要注意:Link Text定位只对 <a> 标签有效。如果你遇到的是 <button> 或者 <div> 模拟的链接,那就不能用这个方法了。
我曾经遇到过一个坑:页面上有两个链接,文本分别是「联系我们」和「联系客服」。我用 PARTIAL_LINK_TEXT 定位「联系」,结果找到了第一个。后来我改成精确匹配,才解决了问题。所以,能用精确匹配就别用部分匹配,除非你确定文本是唯一的。
注意:链接文本里的空格、换行、特殊字符都会影响匹配结果。比如「关于我们」和「关于 我们」就是两个不同的文本。建议先复制页面上的原文,再粘贴到代码里。
3.6 五种定位方式对比总结
好了,五种定位方式都讲完了。咱们来做个对比,方便你以后选择:
| 定位方式 | 依据属性 | 唯一性 | 速度 | 推荐场景 |
|---|---|---|---|---|
| ID定位 | id | 通常唯一 | 最快 | 有静态ID的元素,优先选择 |
| Name定位 | name | 可能不唯一 | 快 | 表单元素、输入框 |
| Class Name定位 | class | 不唯一 | 中等 | 批量获取同类元素 |
| Tag Name定位 | 标签名 | 不唯一 | 中等 | 统计、批量操作 |
| Link Text定位 | 链接文本 | 通常唯一 | 快 | 超链接、导航菜单 |
最后说一句:没有最好的定位方式,只有最合适的。实际项目中,我经常是几种定位方式混着用。比如先用ID定位到某个容器,再用Class Name定位容器里的子元素。这种组合拳,往往比单一方式更稳。
下一章,咱们接着聊CSS选择器和XPath定位。这两种方式更灵活,但也更复杂。准备好了吗?