gpt4 book ai didi

python - BeautifulSoup 错误地检查 NavigableString 元素的子成员身份?

转载 作者:太空宇宙 更新时间:2023-11-03 18:23:12 25 4
gpt4 key购买 nike

我有一个 HTML 页面,其树的一部分看起来像这样(请参阅下面包含 html 的代码片段):

                       <body>
| |
| |
<div id="Kentucky"> <div id="NewOrleans">
| |
| |
Bourbon Bourbon

为什么BeautifulSoup表明“左”波本威士忌是“Kentucky”(正确)和“NewOrleans”(错误)的子代?

反之亦然,正确的波旁威士忌是“肯塔基州”的子代(不正确)。

整个页面有不同的 html 元素,所有元素都具有相同的文本并不罕见(例如在页眉、页脚)。但现在,在我对某些文本模式执行 find_all() 后,在使用 header.children 或 footer.children 正确识别文本元素是否为其中任一元素的子元素时,我无法信任 BeautifulSoup。

(就像在一家公司中,工程和营销部门都声称某个特定的员工属于他们,仅仅因为她的名字是“Sarah” - 公司中可能有多个 Sarah - first_name 属性是只是该对象的众多对象之一,它不应该仅仅确定身份。)

这样的事情可以避免吗,或者,还有什么方法可以找到找出一个元素的正确子元素?

请注意,NavigableString 类的 MRO 以“str”开头:

<class 'str'>, <class 'bs4.element.PageElement'>, <class 'object'>

我想这似乎表明问题的原因是 BeautifulSoup 是使用字符串比较来确定元素之间的相等(或身份匹配)。

无论这是否确实是问题,是否有替代方案或修复/补丁?

谢谢!

代码:

import re
from bs4 import BeautifulSoup

TEST_HTML = """<!doctype html>
<head><title>A title</title></head>
<html>
<body>
<div id="Kentucky">Bourbon</div>
<div id="NewOrleans">Bourbon</div>
</body>
</html>
"""

def test():
soup = BeautifulSoup(TEST_HTML)

# search for "Bourbon"
re_pattern = re.compile('bourbon', re.IGNORECASE)
text_matches = soup.find_all(text=re_pattern)

# print verbose debug output...
for text_match in text_matches:
print('id: {} - class: {} - text: {} - parent attrs: {}'.\
format(id(text_match),
text_match.__class__.__name__,
text_match.string,
text_match.parent.attrs))
# id: 140609176408136 - class: NavigableString - text: Bourbon - parent attrs: {'id': 'Kentucky'}
# id: 140609176408376 - class: NavigableString - text: Bourbon - parent attrs: {'id': 'NewOrleans'}


kentucky_match = text_matches[0]
kentucky_parent = kentucky_match.parent

new_orleans_match = text_matches[1]
new_orleans_parent = new_orleans_match.parent

# confirm -> all ok...
print(kentucky_parent.attrs) # {'id': 'Kentucky'}
print(new_orleans_parent.attrs) # {'id': 'NewOrleans'}

# get a list of all the children for both kentucky and new orleans
# (this tree traversal is all ok)
ky_children = [child for child in kentucky_parent.children]
no_children = [child for child in new_orleans_parent.children]

# confirm -> all ok...
print([id(child) for child in ky_children]) # [140609176408136]
print([id(child) for child in no_children]) # [140609176408376]


# now, here's the problem!!!
print(kentucky_match in no_children) # True -> wrong!!!!!!!
print(kentucky_match in ky_children) # True

print(new_orleans_match in no_children) # True
print(new_orleans_match in ky_children) # True -> wrong!!!!!!!

最佳答案

这是因为kentucky_matchnew_orleans_match都是 NavigableString 的实例类,它是常规 unicode 的子类字符串。

ky_childrenno_children两者基本上都包含一个字符串列表,在您的情况下它只是 [u'Bourbon'] 。和u'Bourbon' in [u'Bourbon']始终评估为 True 。当in检查是否执行字符串比较,而不是 NavigableString类实例。

换句话说,您的 in检查正在字符串列表中查找字符串。

作为解决方法,您可以使用 id()为您in检查:

ky_children = [id(child) for child in kentucky_parent.children]
print(id(kentucky_match) in no_children) # False
print(id(kentucky_match) in ky_children) # True

关于python - BeautifulSoup 错误地检查 NavigableString 元素的子成员身份?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23717842/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com