BeautifulSoup无法解析嵌套的<p>元素
依赖项:
BeautifulSoup==3.2.1
In: from BeautifulSoup import BeautifulSoup
In: BeautifulSoup('<p><p>123</p></p>')
Out: <p></p><p>123</p>
为什么这两个相邻的标签没有出现在输出中呢?
3 个回答
这个
<p><p>123</p></p>
不是有效的HTML。p
标签不能嵌套在一起。BS会尝试修复这个问题。
当BS遇到第二个<p>
标签时,它会认为第一个p
标签已经结束了,所以它会插入一个关闭的</p>
标签。然后你输入的第二个</p>
标签就没有对应的开始<p>
标签了,所以它会被删除。
这是因为 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>
这只是BS3的解析器在修复你那段有问题的HTML代码。
P元素代表一个段落。它不能包含块级元素(包括P元素自己)。