3、元素定位基础:ID定位、Name定位、Class Name定位、Tag Name定位
好,咱们正式开始聊元素定位。
做浏览器自动化,说白了就两件事:找到元素,操作元素。找都找不到,后面全是白搭。我见过太多新手一上来就写复杂的XPath,结果页面稍微改个结构脚本就崩了。其实,最基础的那几个定位方法,用好了反而最稳。
今天咱们就把ID、Name、Class Name、Tag Name这四种定位方式彻底讲透。
3.1 ID定位:最快、最稳、最推荐
ID在HTML里是唯一的。一个页面里,同一个ID只能出现一次。这是W3C的硬性规定。
所以,用ID定位元素,是效率最高的方式。浏览器查找ID时,内部用了哈希表,几乎是毫秒级返回。我个人习惯是:只要元素有ID,我绝不用其他方法。
来看代码怎么写。以Selenium为例:
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://example.com/login")
# 用ID定位用户名输入框
username_input = driver.find_element(By.ID, "username")
username_input.send_keys("admin")
# 用ID定位登录按钮
login_button = driver.find_element(By.ID, "loginBtn")
login_button.click()
我在项目中遇到过一个问题:某个金融系统的登录页面,开发给按钮的ID是动态生成的,每次刷新都不一样。比如 login_1692345678、login_1692345689。这种情况ID定位就废了。嗯,这里要注意,动态ID不能用,得换其他策略。
3.2 Name定位:表单元素的标配
Name属性在HTML里不要求唯一。多个元素可以有相同的name。但它在表单提交时特别重要——后端接收参数就是靠name。
所以,Name定位在表单场景下非常好用。尤其是登录、注册、搜索这类页面,输入框基本都有name属性。
# 用Name定位密码输入框
password_input = driver.find_element(By.NAME, "password")
password_input.send_keys("my_secret_pwd")
# 用Name定位搜索框
search_box = driver.find_element(By.NAME, "q")
search_box.send_keys("金融自动化")
你想想看,为什么表单元素偏爱name?因为表单提交时,浏览器会把所有带name的字段打包成键值对发到后端。这是HTML表单的底层机制。所以开发一般不会漏掉name属性。
# 当有多个同名元素时,用find_elements
tokens = driver.find_elements(By.NAME, "token")
second_token = tokens[1] # 索引从0开始,第二个是索引1
3.3 Class Name定位:批量操作的利器
Class Name在CSS里用于样式控制。同一个class可以给无数个元素用。所以,Class Name定位天然适合批量操作。
比如,一个金融报表页面,所有数据行都用 class="row-data"。你想遍历每一行,提取数据,用Class Name定位就非常方便。
# 获取所有数据行
rows = driver.find_elements(By.CLASS_NAME, "row-data")
for row in rows:
print(row.text)
但这里有个坑:Class Name不能有空格。如果元素的class是 btn primary large,你不能直接传 "btn primary large"。因为class name定位只支持单个class。
.btn.primary.large,要么用XPath。
我记得有一次,一个交易系统的按钮class是 action-btn submit-btn。我直接用 By.CLASS_NAME, "action-btn submit-btn",结果报错。排查了半天才发现是空格的问题。后来改成 By.CSS_SELECTOR, ".action-btn.submit-btn" 就搞定了。
3.4 Tag Name定位:最不常用,但特定场景很香
Tag Name就是HTML标签名,比如 div、input、a、button、table 等等。
说实话,Tag Name定位我平时用得最少。因为一个页面里同一种标签太多了,定位不够精确。但有两个场景,我会优先考虑它:
- 获取页面所有链接:用
find_elements(By.TAG_NAME, "a")拿到所有超链接,然后提取href属性。 - 获取表格所有行:用
find_elements(By.TAG_NAME, "tr")遍历表格数据。
# 获取页面所有链接
all_links = driver.find_elements(By.TAG_NAME, "a")
for link in all_links:
href = link.get_attribute("href")
print(href)
# 获取表格所有行
all_rows = driver.find_elements(By.TAG_NAME, "tr")
for row in all_rows:
cells = row.find_elements(By.TAG_NAME, "td")
for cell in cells:
print(cell.text)
# 组合使用:先定位表格,再找行
table = driver.find_element(By.ID, "trade-table")
rows = table.find_elements(By.TAG_NAME, "tr")
3.5 四种定位方式对比总结
说了这么多,咱们用一张表总结一下:
| 定位方式 | 唯一性 | 速度 | 推荐场景 | 注意事项 |
|---|---|---|---|---|
| ID | 唯一 | 最快 | 任何有ID的元素 | 动态ID不能用 |
| Name | 不唯一 | 快 | 表单输入框、搜索框 | 注意同名元素用find_elements |
| Class Name | 不唯一 | 较快 | 批量操作、列表遍历 | 不支持复合class(有空格) |
| Tag Name | 不唯一 | 快 | 获取所有链接、表格行 | 常与其他定位组合使用 |
最后说一句我的心得:定位方式没有绝对的优劣,只有合不合适。ID最快,但如果没有ID或者ID是动态的,就别死磕。Name在表单里很香,但遇到同名元素要小心。Class Name适合批量,但别被空格坑了。Tag Name用得少,但特定场景下能让你少写很多代码。
嗯,这四种基础定位方式,是后面所有高级定位(CSS选择器、XPath)的基石。把它们吃透了,后面的路就好走了。