前言
在使用 python + lxml 做网页解析时,string() 是 xpath 中最常用、也最容易踩坑的函数之一。
很多同学会遇到这些问题:
string()能拿到标签内部所有嵌套文本,但是不知道和text()的区别;- 误以为
string()可以批量作用于一组节点,直接返回文本列表; - 分不清
string(.)、string(./p)、string(./p[1])的差异; - 不清楚
string()遇到空节点时返回什么结果。
本文结合日常爬虫实战场景,完整讲解 string() 语法、对比、错误案例、可直接复制的业务代码。
运行环境:python + lxml.etree
一、string() 基础定义
string(node) 函数作用:接收单个节点,递归提取该节点下所有文本内容,合并为一段连续字符串。
包含:当前节点直接文本、所有子节点内部文本(<strong> <br> <span> 等嵌套标签内文字全部取出)。
基础语法形式
string(节点路径)
在当前上下文节点内简写形式:
string(.)
string(.) 等价于 string(self),代表取当前节点自身全部文本。
二、与 text() 核心区别(重中之重)
先准备测试 html:
<td>
<p><strong>capital market day 2015</strong><br>测试文本</p>
</td>
1../p/text()
- 只获取当前节点直接子文本节点,不会深入子标签;
- 存在多个文本片段时,返回字符串列表;
- 无法拿到
<strong>、<span>内部文字。
res = td.xpath('./p/text()')
# 结果:['测试文本']
# <strong> 内部文字丢失
2.string(./p)
- 递归遍历节点下所有层级,收集全部文本;
- 无论多少处文本,最终合并成单个字符串;
- 可以拿到所有嵌套标签内的文字。
res = td.xpath('string(./p)')
# 结果:'capital market day 2015测试文本'
直观对比表
| 表达式 | 返回类型 | 能否获取嵌套标签文字 |
|---|---|---|
./p/text() | list[str] | ❌ 不能 |
string(./p) | str | ✅ 可以 |
三、实战分层案例
沿用你项目中真实的表格结构 html
<td>
<p>capital market day 2015:
 </p>
<p>andritz group, wolfgang leitner</p>
<p>schuler group, stefan klebert</p>
</td>上下文节点:td_node
案例1:获取第一个p标签完整文本
# xpath下标从1开始
top_title = td_node.xpath('string(./p[1])').strip()
✅ 正确,可以拿到 <br> 前后所有文本。
❌ 经典错误:./p[0]
xpath不存在0号索引,匹配不到节点,string() 返回空字符串。
案例2:最容易踩坑:string() 不能批量处理一组节点
很多新手会写出下面代码,期望返回文本列表:
# ❌ 错误写法!
text_list = td_node.xpath('string(./p)')
print(text_list)
# 只会返回第一个p的文本,不是列表!原理:string() 只接受单个节点。当路径匹配到多个节点集合时,string() 只会作用于集合里第一个节点,最终结果是单个字符串,不会生成列表。
✅ 正确方案:先获取节点列表,循环调用 string()
p_nodes = td_node.xpath('./p')
text_list = [p.xpath('string()').strip() for p in p_nodes]
p.xpath('string()') 等价于 p.xpath('string(.)'),读取当前p节点全部文本。
案例3:提取第2个及以后所有p标签文本(你的业务场景)
# 筛选position>1的p节点
p_nodes = td_node.xpath('./p[position() > 1]')
content_list = [p.xpath('string()').strip() for p in p_nodes]
案例4:string(.) 在循环节点中的使用
tr_nodes = tree.xpath('//table/tr')
for tr in tr_nodes:
# 提取当前tr下第一个td全部文本
title = tr.xpath('string(./td[1])').strip()
四、string() 边界特性
- 如果传入路径匹配不到任何节点
string()返回空字符串"",不会抛出异常;
# 页面不存在p[99]
res = td_node.xpath('string(./p[99])')
print(res == "") # true
- 文本中包含
( 不间断空格)string()会原样读入,建议统一清洗:
import re
def clean_text(raw):
if not raw:
return ""
# 将所有空白(换行、多个空格、不间断空格)统一替换为单个空格
return re.sub(r"\s+", " ", raw).strip()
- 节点内部只有标签、无任何文字
string()返回空字符串。
五、高频错误汇总
错误1:企图用 string() 批量获取多个节点文本
# ❌ 错误
list_data = td.xpath('string(./p[position()>1])')
# ✅ 正确
p_list = td.xpath('./p[position()>1]')
list_data = [clean_text(p.xpath('string()')) for p in p_list]错误2:混淆 text() 与 string(),丢失嵌套文字
页面存在 <b> <strong> <a> 嵌套文本时,只用 text() 会丢失内容,优先使用 string()。
错误3:在括号位置产生混淆
string((//div[@class="box"])[2]) # ✅ 全局第二个div,取内部文本 string(//div[@class="box"][2]) # ❌ 语义错误,含义完全不同
错误4:python列表下标 和 xpath下标混用
# xpath表达式内部:[1]
td.xpath('string(./p[1])')
# python代码层面:[0] 是列表取值
p_nodes = td.xpath('./p')
text = p_nodes[0].xpath('string()')不要把 python [0] 的习惯直接写到 xpath 字符串中。
六、常用表达式速查表
| 表达式 | 作用说明 |
|---|---|
string(.) | 获取当前节点所有文本 |
string(./p[1]) | 当前节点下第一个p全部文本 |
string(./p[1]/strong) | 当前p内部strong标签文本 |
(//div[@class="demo"])[1]/string(.) | 全局第一个匹配div的全部文本 |
七、可直接复制完整爬虫模板
适配你抓取表格 <td> 内多段 <p> 场景
import re
from lxml import etree
def clean_text(raw_text):
if not raw_text:
return ""
return re.sub(r"\s+", " ", raw_text).strip()
html = """
<td>
<p>capital market day 2015:
 </p>
<p>andritz group, wolfgang leitner</p>
<p>schuler group, stefan klebert</p>
</td>
"""
tree = etree.html(html)
td_list = tree.xpath("//td")
for td in td_list:
# 标题:第一个p文本
title = clean_text(td.xpath('string(./p[1])'))
# 内容列表:第2个及之后所有p
p_nodes = td.xpath('./p[position() > 1]')
content_list = [clean_text(p.xpath('string()')) for p in p_nodes]
print("标题:", title)
print("名单:", content_list)八、总结
string(node)接收单个节点,递归提取所有层级文本,合并为一段字符串;- 无法批量作用于节点集合,想要列表必须先选出节点,循环执行
string(); - 和
text()最大区别:text()只取直接文本,无法获取嵌套标签内容; - xpath 索引从 1 开始,找不到节点时
string()返回空字符串,不会报错; - 处理爬虫网页文本,存在
<strong> <a> <br>嵌套时,优先选择string()。
到此这篇关于python xpath string() 完整使用案例详解|爬虫高频函数避坑(lxml)的文章就介绍到这了,更多相关python xpath string() 语法内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论