有没有一种方法可以在BeautifulSoup解析树上执行DFT(深度优先遍历)?我试图做的是从根节点开始,通常是,获取所有子元素,然后对于每个子元素获取它们的子元素,等等,直到我到达一个叶节点,在这一点上,我将构建回到树。问题是,我似乎找不到一种方法来实现这一点。我找到了findChildren方法,但似乎只是将整个页面多次放入列表中,每个后续条目都会减少。我可能可以使用此方法进行遍历,但除了列表中的最后一个条目之外,似乎没有任何方法将条目标识为终端节点还是非终端节点。有什么想法吗?
有没有一种方法可以在BeautifulSoup解析树上执行DFT(深度优先遍历)?我试图做的是从根节点开始,通常是,获取所有子元素,然后对于每个子元素获取它们的子元素,等等,直到我到达一个叶节点,在这一点上,我将构建回到树。问题是,我似乎找不到一种方法来实现这一点。我找到了findChildren方法,但似乎只是将整个页面多次放入列表中,每个后续条目都会减少。我可能可以使用此方法进行遍历,但除了列表中的最后一个条目之外,似乎没有任何方法将条目标识为终端节点还是非终端节点。有什么想法吗?
mytag.find_all()
已经可以做到这一点:
如果你调用 mytag.find_all(),Beautiful Soup 将会检查 mytag 的所有后代节点:它的子节点、子节点的子节点等等。
from bs4 import BeautifulSoup # pip install beautifulsoup4
soup = BeautifulSoup("""<!doctype html>
<div id=a>A
<div id=1>A1</div>
<div id=2>A2</div>
</div>
<div id=b>B
<div id=I>BI</div>
<div id=II>BII</div>
</div>
""")
for div in soup.find_all("div", recursive=True):
print(div.get('id'))
a
1
2
b
I
II
旧版Beautiful Soup 3的答案:
recursiveChildGenerator()
已经实现了这个功能:
soup = BeautifulSoup.BeautifulSoup(html)
for child in soup.recursiveChildGenerator():
name = getattr(child, "name", None)
if name is not None:
print name
elif not child.isspace(): # leaf node, don't print spaces
print child
对于来自@msalvadores的答案的HTML:
html
ul
li
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
li
Aliquam tincidunt mauris eu risus.
li
Vestibulum auctor dapibus neque.
html
注意:由于示例包含两个开放的<html>
标签,因此html
会打印两次。
recursiveChildGenerator()
已更名为descendants()
。 - J. Taylordescendants
(一个属性,所以没有括号)的文档说明它执行广度优先遍历。我不确定这个答案是否仍适用于当前的bs4版本? - Charles Langloisfind_all(recursive=True)
。我已经更新了答案。 - jfssoup.find_all(recursive=True)
代替soup.find_all("div", recursive=True)
可以简单地获取所有子元素。 - Bálint Sass我认为你可以使用"childGenerator"方法,并递归地使用它以深度优先的方式解析树结构。
def recursiveChildren(x):
if "childGenerator" in dir(x):
for child in x.childGenerator():
name = getattr(child, "name", None)
if name is not None:
print "[Container Node]",child.name
recursiveChildren(child)
else:
if not x.isspace(): #Just to avoid printing "\n" parsed from document.
print "[Terminal Node]",x
if __name__ == "__main__":
soup = BeautifulSoup(your_data)
for child in soup.childGenerator():
recursiveChildren(child)
使用"childGenerator" in dir(x)
,我们可以确定一个元素是否是容器,像NavigableStrings
这样的终端节点不是容器,也不包含子节点。
例如,对于以下HTML:
<html>
<ul>
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
<li>Aliquam tincidunt mauris eu risus.</li>
<li>Vestibulum auctor dapibus neque.</li>
</ul>
</html>
[Container Node] ul
[Container Node] li
[Terminal Node] Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
[Container Node] li
[Terminal Node] Aliquam tincidunt mauris eu risus.
[Container Node] li
[Terminal Node] Vestibulum auctor dapibus neque.
dir()
,.__dict__
使用hasattr()
代替。3. x
已经具备所需的字符串方法;你不需要使用str(x)
(这是多余的,如果x
包含非ASCII字符,它将失败) - jfs