为何BeautifulSoup find_all带string参数无法返回含<br>的元素?
关于BeautifulSoup中find_all的string参数疑问
环境
- Python 3.9.4
- beautifulsoup4==4.12.2
测试代码
from bs4 import BeautifulSoup test_content = '''<html><head></head><body><p>123</p><p>123<br>123</p></body></html>''' bs = BeautifulSoup(test_content, 'html.parser')
问题现象
执行代码后出现如下结果:
>>> bs.find_all('p') [<p>123</p>, <p>123<br/>123</p>] >>> bs.find_all('p', string=True) [<p>123</p>] >>> import re >>> bs.find_all('p', string=re.compile('.+')) [<p>123</p>]
存在两个疑问:
- 为什么添加
string=True后,find_all无法返回包含<br>标签的<p>元素? - 如何查找所有(含或不含
<br>标签)且包含特定关键词的元素?实际场景需要筛选含特定关键词的元素,比如用string=re.compile('KEYWORD'),但直接不传入string参数无法满足筛选需求。
问题解答
1. string=True过滤含子标签元素的原因
BeautifulSoup的string参数匹配的是元素的.string属性值。当元素包含子标签(比如<br>)时,该元素的.string会返回None——因为元素有多个子节点(文本节点+标签节点),BeautifulSoup无法确定返回哪部分文本,此时string=True的匹配条件不成立,所以这类元素会被排除。
比如第二个<p>标签包含<br>子元素,执行bs.find_all('p')[1].string会得到None,自然不满足string=True的条件。
2. 筛选含特定关键词的所有<p>元素(含子标签)
要匹配元素内所有文本内容(包括子标签中的文本),不能依赖string参数,需要用自定义筛选函数结合.get_text()方法来实现:
方法一:基础关键词匹配
def has_target_keyword(tag): # 先判断标签是p,再检查文本中是否包含目标关键词 return tag.name == 'p' and '123' in tag.get_text(strip=True) # 执行筛选 result = bs.find_all(has_target_keyword) print(result) # 输出:[<p>123</p>, <p>123<br/>123</p>]
方法二:正则表达式匹配
如果需要用正则匹配复杂关键词,可在函数中结合re模块:
import re def match_target_pattern(tag): if tag.name != 'p': return False # 获取元素所有文本并去除首尾空白 full_text = tag.get_text(strip=True) # 用正则检查是否匹配 return re.search(r'123', full_text) is not None # 执行筛选 result = bs.find_all(match_target_pattern) print(result)
这两种方法都会把包含子标签的<p>元素纳入筛选范围,只要其文本内容符合关键词要求。
内容的提问来源于stack exchange,提问作者wings
相关产品推荐
相关产品推荐

