XPath中text方法和string方法的用法总结

1 目标

目标网址(丁香园论坛):http://www.dxy.cn/bbs/thread/626626#626626
目标:提取第一个回复的所有内容,如下图所示:
在这里插入图片描述

2. 实战说明

2.1 前期代码准备

import requests # 导入报错的朋友手动安装一下pip install requests
from lxml import etree # 导入报错的朋友手动安装一下pip install lxml

# get_html_text(url)获取网页信息
def get_html_text(url):
    try:
        r = requests.get(url) # 爬取完整的网页数据
        r.raise_for_status() # 如果状态不是200,引发HTTPError异常
        return r.text # 以字符串的形式返回爬取的网页内容
    except:
        print("访问出错")
        return "" # 发生异常,返回空字符串

url = 'http://www.dxy.cn/bbs/thread/626626#626626'
data = get_html_text(url)
# 做好ElementTree
tree = etree.HTML(data)
# 以列表形式,返回所有包含所需信息的td标签
ls = tree.xpath('//td[@class="postbody"]')

n = len(ls) # 统计ls里面有几个元素
print('取到的td标签数:{}'.format(n)) # 输出是4,因为未登录只能抓到4条记录
# 因为第一条是问题,所以第二条才是第一个回复,因此用ls[1]取到
# 下面就是测试语句,展示text()和string的区别了

2.2 text()方法

text()又有两种用法,一种是ls[1].xpath(’./text()’),一种是ls[1].xpath(’.//text()’)。

2.2.1 ls[1].xpath(’./text()’)用法

表示只取当前节点中的文本内容,对于子孙节点的内容不会取。
测试代码:

print('输出取到的文本数目:', end='')
print(len(ls[1].xpath('./text()')))
# 输出取到的文本列表
print("处理前:")
print(ls[1].xpath('./text()'))
# 把列表中的元素合成一个字符串,同时清理组合字符串两端的空格和换行符
print("处理后:")
print('\n'.join(ls[1].xpath('./text()')).strip())

输出结果:

取到的td标签数:4
输出取到的文本数目:4
处理前:
['\n \n 从发作的症状上比较符合血管迷走神经性晕厥,直立倾斜试验能协助诊断。在行直立倾斜实验前应该做常规的体格检查、ECG、UCG、holter和X-ray胸片除外器质性心脏病。', '贴一篇“口服氨酰心安和依那普利治疗血管迷走性晕厥的疗效观察”', '作者:林文华 任自文 丁燕生', '\n \t ']
处理后:
从发作的症状上比较符合血管迷走神经性晕厥,直立倾斜试验能协助诊断。在行直立倾斜实验前应该做常规的体格检查、ECG、UCG、holter和X-ray胸片除外器质性心脏病。
贴一篇“口服氨酰心安和依那普利治疗血管迷走性晕厥的疗效观察”
作者:林文华 任自文 丁燕生

在这里插入图片描述

我们发现:td标签的子标签a中的文本内容"http://www.ccheart.com.cn/ccheart_site/Templates/jieru/200011/1-1.htm"没有被提取出来。

2.2.2 ls[1].xpath(’.//text()’)用法

表示取当前节点及其子孙节点中的文本内容。
测试代码:

print('输出取到的文本数目:', end='')
print(len(ls[1].xpath('.//text()')))
# 输出取到的文本列表
print("处理前:")
print(ls[1].xpath('.//text()'))
# 把列表中的元素合成一个字符串,同时清理组合字符串两端的空格和换行符
print("处理后:")
print('\n'.join(ls[1].xpath('.//text()')).strip())

结果输出:

取到的td标签数:4
输出取到的文本数目:5
处理前:
['\n \n 从发作的症状上比较符合血管迷走神经性晕厥,直立倾斜试验能协助诊断。在行直立倾斜实验前应该做常规的体格检查、ECG、UCG、holter和X-ray胸片除外器质性心脏病。', '贴一篇“口服氨酰心安和依那普利治疗血管迷走性晕厥的疗效观察”', '作者:林文华 任自文 丁燕生', 'http://www.ccheart.com.cn/ccheart_site/Templates/jieru/200011/1-1.htm', '\n \t ']
处理后:
从发作的症状上比较符合血管迷走神经性晕厥,直立倾斜试验能协助诊断。在行直立倾斜实验前应该做常规的体格检查、ECG、UCG、holter和X-ray胸片除外器质性心脏病。
贴一篇“口服氨酰心安和依那普利治疗血管迷走性晕厥的疗效观察”
作者:林文华 任自文 丁燕生
http://www.ccheart.com.cn/ccheart_site/Templates/jieru/200011/1-1.htm

我们看到输出取到的文本数目:5,之前是4,就是因为把字标签a标签中的文本“http://www.ccheart.com.cn/ccheart_site/Templates/jieru/200011/1-1.htm”取到了。

2.3 string()方法

string()会把当前节点和所有的子孙节点中的文本全部提取出来,组合成一个字符串。
测试代码:

print('输出取到的文本数目:', end='')
print(len(ls[1].xpath('string(.)')))
# 输出取到的文本列表
print("处理前:")
print(ls[1].xpath('string(.)'))
# 把列表中的元素合成一个字符串,同时清理组合字符串两端的空格和换行符
print("处理后:")
print(ls[1].xpath('string(.)').strip())

输出结果

取到的td标签数:4
输出取到的文本数目:648
处理前:

                                                                                                                                   
                                                                                                    从发作的症状上比较符合血管迷走神经性晕厥,直立倾斜试验能协助诊断。在行直立倾斜实验前应该做常规的体格检查、ECG、UCG、holter和X-ray胸片除外器质性心脏病。贴一篇“口服氨酰心安和依那普利治疗血管迷走性晕厥的疗效观察”作者:林文华 任自文 丁燕生http://www.ccheart.com.cn/ccheart_site/Templates/jieru/200011/1-1.htm
                                                                                                                                                                                                                                
处理后:
从发作的症状上比较符合血管迷走神经性晕厥,直立倾斜试验能协助诊断。在行直立倾斜实验前应该做常规的体格检查、ECG、UCG、holter和X-ray胸片除外器质性心脏病。贴一篇“口服氨酰心安和依那普利治疗血管迷走性晕厥的疗效观察”作者:林文华 任自文 丁燕生http://www.ccheart.com.cn/ccheart_site/Templates/jieru/200011/1-1.htm

分析结果发现输出的效果没有text()优雅,跟网页预览有差距,连接不同节点的字符串没有加换行符。不过提取的还是很靠谱的。

3. 总结用法

个人感觉string()不够优雅,有点坑,非要写成string(.)的形式,而且还不能在一开始的路径中写,比如:ls = tree.xpath(’//td[@class=“postbody”]/string(.)’)就会报错,而text()就可以。
然后对于text()用’//text()‘还是’/text()'就看你的需求了。
最后放上一波总结的核心代码,以后好直接套用:

# text()的用法
ls = tree.xpath('//td[@class="postbody"]')
'\n'.join(ls[1].xpath('.//text()')).strip()

# string()的用法
ls = tree.xpath('//td[@class="postbody"]')
ls[1].xpath('string(.)').strip()

4. 参考资料

  1. 解决:xpath取出指定多标签内所有文字text

后记:
我从本硕药学零基础转行计算机,自学路上,走过很多弯路,也庆幸自己喜欢记笔记,把知识点进行总结,帮助自己成功实现转行。
2020下半年进入职场,深感自己的不足,所以2021年给自己定了个计划,每日学一技,日积月累,厚积薄发。
如果你想和我一起交流学习,欢迎大家关注我的微信公众号每日学一技,扫描下方二维码或者搜索每日学一技关注。
这个公众号主要是分享和记录自己每日的技术学习,不定期整理子类分享,主要涉及 C – > Python – > Java,计算机基础知识,机器学习,职场技能等,简单说就是一句话,成长的见证!
每日学一技

<think>好的,用户现在想了解在IntelliJ IDEA中使用Selenium时如何通过XPath定位元素。首先,我需要确认用户的基本需求。他们可能正在学习自动化测试,特别是使用Selenium进行Web测试,而XPath是定位元素的重要方法之一。用户可能已经掌握了基本的Selenium用法,但需要更详细的XPath指导。 接下来,我应该考虑用户可能的痛点。XPath的语法可能对他们来说有些复杂,特别是绝对路径相对路径的区别。另外,动态元素的处理,比如如何处理带有变化ID或属性的元素,可能也是他们关心的问题。此外,性能优化方面,比如为什么有时使用XPath效率不高,如何优化XPath表达式,这些也是常见的问题。 然后,我需要整理回答的结构。首先介绍XPath的基本概念,然后讲解在IDEA中如何编写调试XPath,包括绝对路径相对路径的对比,以及常用的定位技巧。接着,可能需要提到动态元素的处理,比如使用contains、starts-with等函数。然后,可以给出一些代码示例,展示如何在Selenium中使用XPath定位元素,并加入断言异常处理。最后,补充一些最佳实践工具推荐,比如Chrome的XPath检查工具,以及性能优化的建议。 还要注意用户之前的问题是关于测试方法命名的,现在转向XPath的具体使用,可能他们在实际编写测试用例时遇到了元素定位的问题。所以,结合之前的测试方法命名规范,给出实际的XPath应用示例,可能对他们更有帮助。 需要确保回答清晰易懂,避免使用过于专业的术语,但又要准确。例如,解释相对路径时,可以对比绝对路径,说明相对路径的优点,比如更简洁、不易受页面结构变化影响。同时,提供具体的例子,比如通过文本内容、属性值来定位元素,这样用户可以直接参考使用。 另外,用户可能在实践中遇到XPath定位不到元素的情况,所以需要强调等待机制动态属性的处理,比如使用显式等待或自定义等待条件,确保元素加载完成后再进行操作。这部分内容对于提高测试的稳定性很重要,用户可能没有意识到这一点,需要特别指出。 最后,考虑到用户可能使用IntelliJ IDEA,可以推荐一些IDEA的插件或内置功能,比如XPath的实时检查工具,或者如何在IDEA中调试XPath表达式,这能提升他们的开发效率。同时,提醒他们避免常见的XPath错误,比如冗余的路径、过于复杂的表达式,以及依赖页面结构等,这些都能帮助他们写出更健壮的测试代码。</think>以下是在IntelliJ IDEA中使用Selenium通过XPath定位元素的详细指南: ### 🔍 XPath定位原理 XPath是XML路径语言,通过节点路径定位网页元素,支持: - 绝对路径:`/html/body/div[2]/form/input` - 相对路径:`//input[@id='username']` - 属性组合:`//*[@class='btn' and contains(text(),'提交')]` ### 🛠️ IDEA实战操作 ```java // 基础定位示例 WebElement searchInput = driver.findElement(By.xpath("//input[@name='q']")); WebElement submitBtn = driver.findElement(By.xpath("//button[text()='搜索']")); // 动态元素处理(包含部分ID) WebElement dynamicItem = driver.findElement( By.xpath("//div[contains(@id,'item_')]") ); // 层级关系定位 WebElement nestedElement = driver.findElement( By.xpath("//form[@id='loginForm']//input[@type='password']") ); ``` ### 📌 定位策略对比表 | 定位方式 | 示例 | 适用场景 | |--------------------------|----------------------------------|----------------------| | 绝对路径 | `/html/body/div[2]/form/input` | 固定结构 | | 属性定位 | `//input[@id='email']` | 有唯一属性 | | 文本匹配 | `//a[text()='立即注册']` | 链接/按钮文本 | | 模糊匹配 | `//div[contains(@class,'error')]`| 动态样式 | | 组合条件 | `//input[@type='text' and @name='user']` | 多重校验 | ### 🚀 高级定位技巧 1. **轴定位**(父子/兄弟节点) ```java // 定位父节点 WebElement parent = driver.findElement( By.xpath("//input[@id='child']/parent::div") ); // 定位相邻元素 WebElement sibling = driver.findElement( By.xpath("//label[text()='用户名']/following-sibling::input") ); ``` 2. **动态属性处理** ```java // 部分属性匹配 WebElement partialMatch = driver.findElement( By.xpath("//*[starts-with(@id,'btn_')]") ); // 正则表达式匹配(XPath 2.0+) WebElement regexMatch = driver.findElement( By.xpath("//div[matches(@class,'col-md-\d+')]") ); ``` 3. **表格定位** ```java // 定位第三行第二列的单元格 WebElement cell = driver.findElement( By.xpath("//table[@id='dataTable']/tbody/tr[3]/td[2]") ); // 根据内容定位行 WebElement targetRow = driver.findElement( By.xpath("//tr[td[text()='2023'] and td[text()='Q4']]") ); ``` ### ⚠️ 常见错误解决方案 1. **元素未找到异常** ```java // 增加显式等待 WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10)); WebElement element = wait.until(ExpectedConditions.presenceOfElementLocated( By.xpath("//div[@class='loading' and @style='display: none;']") )); ``` 2. **性能优化建议** ```java // 避免全量扫描(低效写法) // "//div//input" -> 改进为 "//div[@class='form-group']/input" // 减少通配符使用(低效写法) // "//*[@id='container']/div" -> 改进为 "//div[@id='container']/div" ``` ### 🔧 IDEA调试技巧 1. **实时验证XPath** - 在Chrome开发者工具中: - 按`Ctrl+F`打开搜索框 - 输入XPath表达式实时验证 - 匹配元素会高亮显示 2. **XPath生成工具**(Chrome扩展推荐) - ChroPath - XPath Helper - SelectorsHub 3. **断点调试配置** ```java // 在定位代码前设置断点 driver.findElement(By.xpath("//button[contains(@class, 'confirm-btn')]")).click(); // 在此行设置断点 // 运行时查看元素状态: // 1. 使用Evaluate Expression工具(Alt+F8) // 2. 输入driver.findElement(...).isDisplayed() 验证可见性 // 3. 检查元素属性值 ``` ### 📝 最佳实践清单 1. **优先级选择策略**: - 首选ID/Name等稳定属性 - 次选class/text等半稳定属性 - 最后考虑层级结构 2. **容错处理建议**: ```java // 添加try-catch块处理动态元素 try { WebElement element = driver.findElement(By.xpath("//div[@data-status='ready']")); } catch (NoSuchElementException e) { System.out.println("元素未加载完成,启动重试机制"); // 添加重试逻辑 } ``` 3. **跨浏览器兼容**: ```java // 处理不同浏览器的XPath解析差异 String xpath = ""; if (browser.equals("firefox")) { xpath = "//*[local-name()='svg']"; // Firefox的SVG处理方式 } else { xpath = "//svg"; // Chrome的常规写法 } ``` ### 🧪 完整测试案例 ```java public class XPathDemoTest { WebDriver driver; @BeforeEach void setup() { driver = new ChromeDriver(); driver.get("https://example.com/login"); } @Test void testLoginWithValidXPath() { // 使用组合条件定位 WebElement username = driver.findElement( By.xpath("//input[@type='text' and @name='username']") ); username.sendKeys("testuser"); // 使用相邻元素定位 WebElement password = driver.findElement( By.xpath("//label[text()='密码:']/following-sibling::input") ); password.sendKeys("password123"); // 使用属性包含定位 driver.findElement( By.xpath("//button[contains(@class,'submit-btn')]") ).click(); // 验证结果 WebElement welcome = driver.findElement( By.xpath("//h1[starts-with(text(),'欢迎')]") ); assertTrue(welcome.isDisplayed()); } @AfterEach void teardown() { driver.quit(); } } ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值