Selenium中如何通过XPath获取父节点下无标签包裹的文本
问题根因
原有定位代码无法拿到目标文本,核心原因有两个:
- XPath末尾的
/*语法只会匹配目标div下的子元素节点(即label、br这类HTML标签),不会匹配直接归属于div、没有被任何标签包裹的文本节点 presence_of_element_located方法仅会返回匹配到的第一个DOM元素,最终只能拿到第一个label标签内的"Brand Name:"文本,完全触达不到目标无标签内容
正确实现方案
注意:Selenium自带的find_element/find_elements系列方法仅支持返回DOM元素节点,无法直接识别XPath选出的文本节点,不要尝试直接写/text()后缀的XPath配合元素定位方法取值,会触发定位失败异常。
方法1:JavaScript提取(推荐,稳定性最高)
先定位到目标父div容器(建议替换掉原有的绝对路径XPath,用class属性组合的选择器定位,抗页面结构变动能力更强),再通过JS遍历父节点的所有子节点,筛选出纯文本节点、过滤空白内容即可:
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By # 定位父div容器 parent_div = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, "div.xsmall-12.medium-6.columns")) ) # 执行JS提取所有直接子文本节点 target_texts = driver.execute_script(""" const parentNode = arguments[0]; const res = []; for (const node of parentNode.childNodes) { // 筛选文本节点,过滤换行、空格类无意义空白 if (node.nodeType === Node.TEXT_NODE) { const content = node.textContent.trim(); if (content) res.push(content); } } return res; """, parent_div) # 最终返回结果:['Snowden-Pencer', '32-0044', 'In Commercial Distribution', '32-0044', 'CAREFUSION 2200, INC'] print(target_texts)
方法2:文本差量计算(无需写JS)
先获取父节点的全量文本,再剔除所有子label标签内的文本,剩余内容拆分过滤后就是目标值:
parent_div = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, "div.xsmall-12.medium-6.columns")) ) # 获取父节点下所有文本 full_text = parent_div.text # 获取所有子label内的文本 label_contents = [label.text for label in parent_div.find_elements(By.TAG_NAME, "label")] # 替换掉所有label文本,拆分后过滤空白项 for content in label_contents: full_text = full_text.replace(content, "") target_texts = [item.strip() for item in full_text.split("\n") if item.strip()]
优化提示:原代码中从
<html>根节点开始写的绝对XPath可维护性极差,页面只要调整一层节点结构就会定位失效,生产环境尽量使用相对路径、class/属性选择器定位元素。
内容的提问来源于stack exchange,提问作者Reenath Reddy Thummala
相关产品推荐
相关产品推荐

