导读:本期聚焦于周翰文创作的《如何正确使用 Selenium 定位多个 HTML 元素并提取文本内容》,敬请观看详情。Selenium 自动化测试中,定位单个元素和定位多个元素的方法存在明显区别,用错方法常常导致脚本报错或只能拿到第一条数据。本文详细讲解 find_element 与 find_elements 的差异,介绍如何借助 By 类配合 CLASS_NAME、CSS_SELECTOR、XPATH 等策略批量获取页面元素列表,并演示循环遍历提取文本内容的完整写法。同时分析了元素未加载、隐式等待与显式等待的使用时机,以及动态加载页面下提取不到文本的常见原因和解决办法,帮助读者写出稳定可靠的网页数据采集与自动化脚本。

Selenium 是目前最流行的 Web 自动化工具之一,无论是做自动化测试还是网页数据采集,都绕不开一个核心问题:如何定位页面上的多个元素,并把它们的文本内容提取出来。很多初学者会在这里踩坑,比如把 find_elementfind_elements 混用,或者定位到了元素列表却发现取出来的文本是空的。本文将系统地讲解多个元素定位与文本提取的正确姿势。

如何正确使用 Selenium 定位多个 HTML 元素并提取文本内容

一、find_element 与 find_elements 的区别

这是初学者最容易混淆的地方。Selenium 提供了两个非常相似的方法:find_elementfind_elements。前者只返回页面中匹配定位条件的第一个元素,返回类型是 WebElement;后者返回所有匹配的元素,返回类型是一个列表 list,即使页面上只有一个元素匹配,返回的也是包含一个元素的列表;如果一个都没匹配到,find_element 会抛出 NoSuchElementException 异常,而 find_elements 则返回一个空列表,不会报错。

举个例子,页面上有 10 个商品的标题,如果你想全部拿到,就必须用 find_elements。如果你误用了 find_element,脚本不会报错,但永远只能拿到第一条数据,这种逻辑错误往往很难察觉。在实际编码时,建议根据业务需求明确选择:需要批量操作用 find_elements,只操作某一个特定元素用 find_element

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://ipipp.com/demo")

# find_element:只返回第一个匹配的元素
first_item = driver.find_element(By.CLASS_NAME, "item-title")
print(first_item.text)

# find_elements:返回所有匹配的元素组成的列表
all_items = driver.find_elements(By.CLASS_NAME, "item-title")
for item in all_items:
    print(item.text)

driver.quit()

二、常用的八种定位策略与批量定位写法

在新版本的 Selenium(4.x)中,定位元素推荐使用 By 类来指定定位策略,写法为 driver.find_elements(By.XXX, "定位值")。常用的策略包括:By.IDBy.NAMEBy.CLASS_NAMEBy.TAG_NAMEBy.LINK_TEXTBy.PARTIAL_LINK_TEXTBy.CSS_SELECTORBy.XPATH。其中适合批量定位的主要是后四种,因为 ID 通常要求全页唯一,用 ID 批量定位意义不大。

By.TAG_NAME 常用于获取某一类标签的全部实例,比如提取页面上所有的表格行或链接。By.CSS_SELECTOR 性能好、语法简洁,例如 .list li .title 可以一次选中列表中所有标题节点。By.XPATH 功能最强,支持文本匹配和层级关系,例如 //div[@class='list']/ul/li 能精确定位某容器下的所有列表项。需要注意的是,By.CLASS_NAME 的值只能是单个 class 名,如果元素的 class 属性包含多个类名如 class="item title red",不能把整个字符串传进去,此时应改用 CSS 选择器 .item.title.red

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://ipipp.com/news")

# 通过标签名批量定位所有链接
links = driver.find_elements(By.TAG_NAME, "a")
for link in links:
    print(link.get_attribute("href"))

# 通过 CSS 选择器定位列表中所有标题
titles = driver.find_elements(By.CSS_SELECTOR, "ul.news-list li span.title")
for t in titles:
    print(t.text)

# 通过 XPATH 定位包含特定文本的所有节点
hot = driver.find_elements(By.XPATH, "//a[contains(text(), '热点')]")
print("包含热点的链接数量:", len(hot))

driver.quit()

三、提取文本的正确方式:text 与 get_attribute

拿到元素列表之后,提取内容主要依赖两个方法。element.text 返回元素的可见文本,也就是渲染后用户能看到的文字,它会自动拼接所有子节点的文本。element.get_attribute("textContent") 则获取 DOM 中的原始文本,包括被 CSS 隐藏的内容;如果想要元素的 HTML 片段,可以使用 get_attribute("innerHTML")

两者的区别在实际项目中非常重要。当元素在页面上处于不可见状态(例如设置了 display:none,或者位于需要滚动才能显示的区域)时,text 可能返回空字符串,而 textContent 依然能拿到内容。另外,如果目标文字写在 value 属性中(比如输入框),就要用 get_attribute("value")text 是取不到的。还有一点需要注意:如果要提取属性而不是文本,比如链接地址、图片地址,应分别使用 get_attribute("href")get_attribute("src")

items = driver.find_elements(By.CSS_SELECTOR, "div.product")

for item in items:
    # 可见文本
    name = item.text
    # 包含隐藏内容的原始文本
    raw = item.get_attribute("textContent")
    # 元素内部 HTML
    html = item.get_attribute("innerHTML")
    print(name, raw[:20], html[:20])

四、页面未加载完导致取不到文本怎么办

批量定位时最常见的问题是明明选择器写对了,find_elements 却返回空列表,或者取到的文本为空。根本原因通常是页面还没加载完,脚本就已经开始定位了。现代网页大量使用异步请求和动态渲染,DOM 是逐步生成的,直接定位自然找不到目标。

解决思路有三种。第一种是设置隐式等待 driver.implicitly_wait(10),它会对后续所有的定位操作生效,在限定时间内不断轮询直到元素出现,适合结构简单的页面。第二种是使用显式等待 WebDriverWait 配合 expected_conditions,例如 presence_of_all_elements_located 等待全部元素出现在 DOM 中,或用 visibility_of_all_elements_located 确保它们可见,这种方式更精确,是推荐做法。第三种是针对需要滚动加载的页面,先执行 driver.execute_script("window.scrollTo(0, document.body.scrollHeight)") 触发懒加载,再结合等待获取元素。要特别提醒的是,隐式等待和显式等待尽量不要混用,否则可能出现难以预测的等待时间。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome()
driver.get("https://ipipp.com/list")

# 显式等待:等待所有目标元素加载完成
wait = WebDriverWait(driver, 15)
items = wait.until(
    EC.presence_of_all_elements_located(
        (By.CSS_SELECTOR, "ul.list li")
    )
)

for item in items:
    print(item.text.strip())

driver.quit()

五、实战建议与常见坑总结

在真实项目中批量提取文本,建议养成几个好习惯。第一,提取文本后调用 strip() 去掉首尾空白,网页源码中的缩进和换行经常混进文本里。第二,对 find_elements 返回的列表先判空再处理,避免页面结构变化导致脚本崩溃。第三,如果元素列表是通过一次 find_elements 拿到的,后续 DOM 变化不会自动同步到这个列表,需要重新执行定位方法刷新列表。第四,提取大量数据时可以配合列表推导式一次性收集结果,代码更简洁。

常见的坑还包括:class 名写成了复合形式导致 InvalidSelectorException;XPath 中使用了单引号包裹的属性值却和 Python 字符串引号冲突(可改用双引号或拼接变量);在 iframe 内的元素没有先执行 driver.switch_to.frame() 就去定位,结果始终找不到。只要理解了等待机制、定位策略和文本提取方法的适用边界,Selenium 的批量元素处理就会变得非常稳定可靠。

Selenium元素定位find_elements修改时间:2026-08-31 15:18:52

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。