BeautifulSoup无法解析嵌套的<p>元素

2 投票
3 回答
694 浏览
提问于 2025-04-18 04:35

依赖项:
BeautifulSoup==3.2.1

In: from BeautifulSoup import BeautifulSoup
In: BeautifulSoup('<p><p>123</p></p>')
Out: <p></p><p>123</p>

为什么这两个相邻的标签没有出现在输出中呢?

3 个回答

2

这个

<p><p>123</p></p>

不是有效的HTML。p标签不能嵌套在一起。BS会尝试修复这个问题。

当BS遇到第二个<p>标签时,它会认为第一个p标签已经结束了,所以它会插入一个关闭的</p>标签。然后你输入的第二个</p>标签就没有对应的开始<p>标签了,所以它会被删除。

2

这是因为 BeautifulSoup 有一个叫做 NESTABLE_TAGS 的概念/设置:

当 Beautiful Soup 在解析一个文档时,它会保持一个打开标签的堆栈。每当它看到一个新的开始标签时,就会把这个标签放到堆栈的顶部。但在此之前,它可能会关闭一些已经打开的标签,并把它们从堆栈中移除。关闭哪些标签取决于它刚找到的标签的特性,以及堆栈中标签的特性。

所以,当 Beautiful Soup 遇到一个 <P> 标签时,它会关闭并弹出所有到达该标签为止的同类型标签。这是默认的行为,也是 BeautifulStoneSoup 对每个标签的处理方式。当一个标签没有在 NESTABLE_TAGS 或 RESET_NESTING_TAGS 中提到时,就会出现这种情况。如果一个标签出现在 RESET_NESTING_TAGS 中,但在 NESTABLE_TAGS 中没有条目,就像 <P> 标签那样,也会出现这种情况。

>>> pprint(BeautifulSoup.NESTABLE_TAGS)
{'bdo': [],
 'blockquote': [],
 'center': [],
 'dd': ['dl'],
 'del': [],
 'div': [],
 'dl': [],
 'dt': ['dl'],
 'fieldset': [],
 'font': [],
 'ins': [],
 'li': ['ul', 'ol'],
 'object': [],
 'ol': [],
 'q': [],
 'span': [],
 'sub': [],
 'sup': [],
 'table': [],
 'tbody': ['table'],
 'td': ['tr'],
 'tfoot': ['table'],
 'th': ['tr'],
 'thead': ['table'],
 'tr': ['table', 'tbody', 'tfoot', 'thead'],
 'ul': []}

作为一种解决方法,你可以允许 p 标签嵌套在另一个 p 标签里面:

>>> from BeautifulSoup import BeautifulSoup
>>> BeautifulSoup.NESTABLE_TAGS['p'] = ['p']
>>> BeautifulSoup('<p><p>123</p></p>')
<p><p>123</p></p>

另外,BeautifulSoup 的第三个版本已经不再维护了 - 你应该切换到 BeautifulSoup4

在使用 BeautifulSoup4 时,你可以更改底层的 解析器 来改变行为:

>>> from bs4 import BeautifulSoup
>>> BeautifulSoup('<p><p>123</p></p>')
<html><body><p></p><p>123</p></body></html>
>>> BeautifulSoup('<p><p>123</p></p>', 'html.parser')
<p><p>123</p></p>
>>> BeautifulSoup('<p><p>123</p></p>', 'xml')
<?xml version="1.0" encoding="utf-8"?>
<p><p>123</p></p>
>>> BeautifulSoup('<p><p>123</p></p>', 'html5lib')
<html><head></head><body><p></p><p>123</p><p></p></body></html>
4

这只是BS3的解析器在修复你那段有问题的HTML代码

P元素代表一个段落。它不能包含块级元素(包括P元素自己)。

撰写回答