Beautiful Soup和Python. 递归获取所有节点时出现“超出最大递归深度”错误

1 投票
1 回答
2372 浏览
提问于 2025-04-18 01:39

我在使用一个叫FreeMind的程序,这个程序可以创建树状结构,并将它们导出为HTML文件。我需要获取这棵树的每一个“路径”,然后把它们放到一个列表里,这样我就可以单独处理每一个“路径”。

enter image description here

比如说,从这段代码中:

<body>
   <p>Example</p>
   <ul>
      <li>
         The First List
         <ul>
            <li>1</li>
            <li>2</li>
            <li>3</li>
         </ul>
      </li>
      <li>
         The Second List
         <ul>
            <li>4.1</li>
            <li>4.2</li>
         </ul>
      </li>
   </ul>
</body>

我需要提取出接下来的几个独立的代码分支:

<body>
   <p>Example</p>
   <ul>
      <li>
         The First List
         <ul>
            <li>1</li>
         </ul>
      </li>
   </ul>
</body>

<body>
   <p>Example</p>
   <ul>
      <li>
         The First List
         <ul>
            <li>2</li>
         </ul>
      </li>
   </ul>
</body>

<body>
   <p>Example</p>
   <ul>
      <li>
         The First List
         <ul>
            <li>3</li>
         </ul>
      </li>
   </ul>
</body>

<body>
   <p>Example</p>
   <ul>
      <li>
         The Second List
         <ul>
            <li>4.1</li>
         </ul>
      </li>
   </ul>
</body>

<body>
   <p>Example</p>
   <ul>
      <li>
         The Second List
         <ul>
            <li>4.2</li>
         </ul>
      </li>
   </ul>
</body>

我尝试了这段代码,但出现了错误:“调用Python对象时超出了最大递归深度”。

from bs4 import BeautifulSoup

parsed = BeautifulSoup(open("example.html"))

body = parsed.body

def all_nodes(obj):
    for node in obj:
        print node
        all_nodes(node)

print all_nodes(body)

我想我应该解释一下我后面想用这些东西做什么。我在FreeMind里写测试用例,并且我正在尝试写一个工具,能够生成一个包含所有测试用例的CSV表格。但现在我只是想把所有的测试用例提取成文本。

1 个回答

2

这里有一种方法可以做到。虽然这并不是最简单或最符合Python风格的做法。我个人不太喜欢这个解决方案,但对你来说应该是一个不错的起点。我敢打赌还有更优雅、更简洁的方法可以实现同样的功能。

这个思路是遍历所有没有子元素的元素。对于每一个这样的元素,递归地遍历它的父元素,直到我们找到body为止:

from bs4 import BeautifulSoup, Tag


data = """
your xml goes here
"""
soup = BeautifulSoup(data)
for element in soup.body.find_all():
    children = element.find_all()
    if not children:
        tag = Tag(name=element.name)
        tag.string = element.string
        for parent in element.parentGenerator():
            parent = Tag(name=parent.name)
            parent.append(tag)
            tag = parent
            if tag.name == 'body':
                break
        print tag

这样会产生:

<body><p>Example</p></body>
<body><ul><li><ul><li>1</li></ul></li></ul></body>
<body><ul><li><ul><li>2</li></ul></li></ul></body>
<body><ul><li><ul><li>3</li></ul></li></ul></body>
<body><ul><li><ul><li>4.1</li></ul></li></ul></body>
<body><ul><li><ul><li>4.2</li></ul></li></ul></body>

更新(也写入父元素的文本):

soup = BeautifulSoup(data)
for element in soup.body.find_all():
    children = element.find_all()
    if not children:
        tag = Tag(name=element.name)
        tag.string = element.string
        for parent in element.parentGenerator():
            parent_tag = Tag(name=parent.name)
            if parent.string:
                parent_tag.string = parent.string
            parent_tag.append(tag)
            tag = parent_tag
            if tag.name == 'body':
                break
        print tag

希望这对你有帮助。

撰写回答