使用BeautifulSoup 4和递归来捕获HTML嵌套标签的结构

GKE*_*GKE 5 python beautifulsoup python-3.x

我一直在尝试使用BeautifulSoup4和递归来捕获HTML页面的布局.我们的想法是将父项的数据结构链接到子项,例如,这样的布局:

<html>
 <h1>
  <!--Contents-->
 </h1>
 <div> 
  <div> 
   <!--Contents-->
  </div>
 </div>
</html>
Run Code Online (Sandbox Code Playgroud)

将存储在如下列表中:

html = [ h1 , div ] # Where h1 and div are also lists also containing lists
Run Code Online (Sandbox Code Playgroud)

我很难找到关于这个特定问题的Q&A,所以我尝试使用递归遍历目录来建模函数,因为它们非常相似.

这是我在Python 3中的当前函数,它应该将标记嵌入到列表中:

def listGen(l , hObj):
    # Where hObj is a BS4 object and l is a sorted lists containing direct children to the html tag
    z = []
    for x in l:
        z.append(hObj.find(x).children)

    def expand(xlist1):
        # Where xlist1 is a list generator 
        for n in xlist1:
            if n.name is not None:
                print(n.name)
                for n2 in hObj.find(n.name).children:
                    if n2.name is not None:
                        print(n2.name , "--") #Debugging print              
        return z #Temporary
    for x in z:
        print("------")
        expand(x , 0)
    return z
Run Code Online (Sandbox Code Playgroud)

解析维基百科主页给出了以下输出:

------
h1
img --
div --
div
div --
strong --
div
div --
strong --
div
div --
strong --
div
div --
strong --
div
div --
strong --
hr
div
div --
strong --
p
small --
small --
small --
script
script
script
style
------
meta
title
meta
script
meta
link
link
link
style
style
link
link
Run Code Online (Sandbox Code Playgroud)

这正是我所需要的,它需要两个for循环,并将需要更多来获得孩子的所有孩子.此外,我不知道有多少标签嵌套在未来的网站上.所以我把expand功能改为:

def expand(xlist1 , depth): 
    l1 = list(xlist1)
    if depth < len(l1):
        for n in l1[depth]:
            if n is not None:
                if hObj.find(l1[depth].name).children:
                    return expand(hObj.find(l1[depth].name).children , 0)
            if n is None:
                print(2) # Debugging print
                return expand(xlist1 , depth + 1)
    if depth >= len(l1):
        return 0 # Temporary
    return 0 # Temporary
Run Code Online (Sandbox Code Playgroud)

只是为了给我最大的递归错误,我尝试了很多其他的变化都无济于事.

我已多次浏览BS4 Docs,似乎没有内置功能.任何建议或这不是一个可行的方式来实现我正在寻找的东西?

小智 5

我不认为嵌套列表正是您在这里寻找的。如果您要做的只是构建一棵标签树,我会使用嵌套字典。如果您尝试提取任何其他信息,我仍然会使用它们。

这个递归函数将构建一个嵌套字典“树”

def traverse(soup):
    if soup.name is not None:
        dom_dictionary = {}
        dom_dictionary['name'] = soup.name
        dom_dictionary['children'] = [ traverse(child) for child in soup.children if child.name is not None]
        return dom_dictionary
Run Code Online (Sandbox Code Playgroud)

我们可以像这样使用它:

page = requests.get("http://example.com")
soup = BeautifulSoup(page.text, "html5lib")
traverse(soup)
Run Code Online (Sandbox Code Playgroud)

这给了我们:

{'name': '[document]',
 'children': [{'name': 'html',
   'children': [{'name': 'head',
     'children': [{'name': 'title', 'children': []},
      {'name': 'meta', 'children': []},
      {'name': 'meta', 'children': []},
      {'name': 'meta', 'children': []},
      {'name': 'style', 'children': []}]},
    {'name': 'body',
     'children': [{'name': 'div',
       'children': [{'name': 'h1', 'children': []},
        {'name': 'p', 'children': []},
        {'name': 'p', 'children': [{'name': 'a', 'children': []}]}]}]}]}]}
Run Code Online (Sandbox Code Playgroud)