Python3:如何根据'h'标记的级别将普通html转换为嵌套字典?

Python3:如何根据'h'标记的级别将普通html转换为嵌套字典?,python,dictionary,beautifulsoup,nested,tuples,Python,Dictionary,Beautifulsoup,Nested,Tuples,我有一个如下所示的html: <h1>Sanctuary Verses</h1> <h2>Purpose and Importance of the Sanctuary</h2> <p>Ps 73:17\nUntil I went into the sanctuary of God; [then] understood I their end.</p> <p>...</p

我有一个如下所示的html:

<h1>Sanctuary Verses</h1>
    <h2>Purpose and Importance of the Sanctuary</h2>
       <p>Ps 73:17\nUntil I went into the sanctuary of God; [then] understood I their end.</p>
       <p>...</p>
    <h2>Some other title</h2>
        <p>...</p>
         <h3>sub-sub-title</h3>
             <p>sub-sub-content</p>
    <h2>Some different title</h2>
        <p>...</p>...

我编写了一些变通代码,帮助我获得所需的输出。我想知道获得所需输出的最简单方法是什么

这是一种堆栈问题/图形问题。我们叫它树吧。(或文件或任何东西。)

我认为您的初始元组可以改进。(文本、深度、类型)

stack=[]
深度=0
破环_值=-1
当前={“标题”:“根”,“内容”:[]}
对于\u元组列表\u中的项:
如果项目[1]>深度:
#更深的
下一步={“标题”:项[0],“内容”:[]
当前[“内容”]。追加(下一步)
stack.append(当前)
当前=下一个
深度=项目[1]
elif项目[1]项目[1]:
prev=stack.pop()
深度=深度-1
当前={“标题”:项[0],“内容”:[]}
堆栈[-1]。追加(当前)
深度=项目[1]
其他:
#相同深度
如果项目[2]==损坏的\u值:
# 元素被添加到当前级别。
当前['contents']。追加(项[0])
其他:
#元素被添加到当前元素的父元素。
当前={“标题”:项[0],“内容”:[]}
堆栈[-1][“内容”]。追加(当前)
破环值=项目[2]
这将创建一个任意深度图,假设深度增加1,但 可以减少任意数量

最好在字典中记录深度,以便一次可以移动多个深度。不只是“标题”和“内容”,而可能是“标题”、“深度”和“内容”

解释
堆栈跟踪打开的元素,我们当前的元素就是我们正在构建的元素

如果我们发现深度>大于当前深度,那么我们将当前元素放在堆栈上(它仍然打开),并开始处理下一级元素

如果深度小于当前元素,我们将关闭当前元素和父元素,使其达到相同的深度


最后,如果深度相同,我们将确定它是刚刚添加的“p”元素,还是关闭电流并启动新电流的另一个“h”。

您可以将递归与
itertools一起使用。groupby

import itertools as it, re
def to_tree(d):
  v, r = [list(b) for _, b in it.groupby(d, key=lambda x:not x[0])], []
  for i in v:
    if r and isinstance(r[-1], dict) and not r[-1]['content']:
      r[-1]['content'] = to_tree([(j[4:], k) for j, k in i])
    else:
      for _, k in i:
        r.append(re.sub('</*\w+\>', '', k) if not re.findall('^\<h', k) else {'title':re.sub('</*\w+\>', '', k), 'content':[]})
  return r
输出:

{
   "title": "Sanctuary Verses",
   "content": [
    {
        "title": "Purpose and Importance of the Sanctuary",
        "content": [
            "Ps 73:17 Until I went into the sanctuary of God; [then] understood I their end.",
            "..."
        ]
    },
    {
        "title": "Some other title",
        "content": [
            "...",
            {
                "title": "sub-sub-title",
                "content": [
                    "sub-sub-content"
                ]
            }
        ]
    },
      {
         "title": "Some different title",
         "content": [
            "..."
         ]
      }
   ] 
} 

您期望的输出是什么。我们是在基于html标记的递归字典中编写字典吗?像
versesDict={'圣所的诗篇':{'圣所的目的和重要性':'>诗73:17\n直到我进入上帝的圣所;[那时]我才明白他们的目的。}
@SamuelMiddendorp我已经添加了想要的输出为什么你决定“目的…”作为h2而“目的…”作为p?他们都有(2,2),所以他们应该是兄弟姐妹,对吗?h2是html中的标题标记,对吗?数据应该是嵌套的。但出于展示的目的,它被制作成了兄弟姐妹。我需要嵌套数据,因此question@OneFace需要考虑的是,字典由键和值组成。每当你想提取一个值,你必须查询这个键。在我看来,如果关键字是文档的标题,而值是文档的子项,那么字典的功能会更好。H1为母体,其内容物为H2的内部。这样,如果你想查询所有subversis(我可能在这里删掉了一些术语,对此很抱歉),你可以只做
print(versesDict['saccession Verses'])
prev=stack.pop()
这不会删除
堆栈的最后一个元素而不是关闭它吗?@OneFace这就是我关闭它的意思。堆栈按深度对所有打开的元素进行排序。因此,如果我们的深度当前为3,下一个元素为2,我们需要删除堆栈中的最后一个元素,可能是深度2,它“关闭”了它,因为它不再在我们的打开项列表中。有几个错误:
current.append(i[0])
必须更改为
current['contents'].append(i[0])
。我必须使用它来理解
堆栈中有不止一个元素,这就是您保持它打开的方式。但这是一段很棒的代码!非常感谢。
import itertools as it, re
def to_tree(d):
  v, r = [list(b) for _, b in it.groupby(d, key=lambda x:not x[0])], []
  for i in v:
    if r and isinstance(r[-1], dict) and not r[-1]['content']:
      r[-1]['content'] = to_tree([(j[4:], k) for j, k in i])
    else:
      for _, k in i:
        r.append(re.sub('</*\w+\>', '', k) if not re.findall('^\<h', k) else {'title':re.sub('</*\w+\>', '', k), 'content':[]})
  return r
import json
result = to_tree([((lambda x:'' if not x else x[0])(re.findall('^\s+', i)), re.sub('^\s+', '', i)) for i in filter(None, html.split('\n'))])
print(json.dumps(result[0], indent=4))
{
   "title": "Sanctuary Verses",
   "content": [
    {
        "title": "Purpose and Importance of the Sanctuary",
        "content": [
            "Ps 73:17 Until I went into the sanctuary of God; [then] understood I their end.",
            "..."
        ]
    },
    {
        "title": "Some other title",
        "content": [
            "...",
            {
                "title": "sub-sub-title",
                "content": [
                    "sub-sub-content"
                ]
            }
        ]
    },
      {
         "title": "Some different title",
         "content": [
            "..."
         ]
      }
   ] 
}