这个问题试图扩展 Jason S 的代码(谢谢,Jason),可以在这里找到:Docutils:遍历部分?.
Jason S 原创
import docutils
def doctree_resolved(app, doctree, docname):
for section in doctree.traverse(docutils.nodes.section):
title = section.next_node(docutils.nodes.Titular)
if title:
print title.astext()
def setup(app):
app.connect('doctree-resolved', doctree_resolved)
现在,假设我只想捕获 H2 小节的文本(或者至少捕获所有小节,如果这是唯一的选择)。
理论上,我正在尝试创建一个小节标题的字典,以及它们各自的网址/路径。 最好的方法是什么?
我对上面原始版本的修改并不成功,但希望您可以通过阅读代码来理解我的方法。我相信,使用列表构建的简单 for 循环并不成功,因为
title = section.next_node(docutils.nodes.Titular)
行,特别是 next_node...
。我查看了,但找不到有关 next_node
的文档。
那么,有什么不同的方法可以实现从每个文档中捕获 H2 小节,以便我可以构建一个字典,其中每个小节都有一个路径/url? 注意:我还没有尝试在下面的代码中构建完整的 URL。
import docutils
docname_list = []
section_list = []
def doctree_resolved(app, doctree, docname):
for section in doctree.traverse(docutils.nodes.section):
title = section.next_node(docutils.nodes.Titular)
if title:
print(title.astext())
docname_list.append(docname)
section_list.append(title.astext())
...
url_dict = dict(zip(docname_list, section_list)
...
获取文档中所有章节标题列表的最简单方法是
from docutils import nodes
def all_section_titles(doctree):
return [section.next_node(nodes.title).astext()
for section in doctree.findall(nodes.section)]
有关使用的元素方法的详细信息,请参阅他们的 Python 文档字符串
help(nodes.Element.findall)
和 help(nodes.Element.next_node)
。
doctree
及其元素的结构和功能在 Docutils 文档树中进行了描述。
由于 Docutils 文档树中的
<section>
元素和 <title>
元素没有 level 属性(或 HTML 中的依赖于级别的名称,如 H1、H2、...),因此 nodes.Element.findall()
方法不能轻易用于获取特定级别的章节/章节标题。
我们必须“手动”遍历子元素。
根据全局文档标题是否存在,HTML 输出可能会使用“H2”HTML 元素作为顶级节标题或子节标题。 以下是两个函数,用于捕获顶级部分和子部分的标题元素:
from docutils import nodes
def top_section_titles(doctree):
return [child.next_node(nodes.title).astext()
for child in doctree
if isinstance(child, nodes.section)]
def sub_section_titles(doctree):
titles = []
for child in doctree:
if not isinstance(child, nodes.section):
continue
for grandchild in child:
if not isinstance(grandchild, nodes.section):
continue
titles.append(grandchild.next_node(nodes.title).astext())
return titles
HTML 文档具有自动生成的节元素锚点。 章节标题到 URL 的映射可以通过以下方式实现:
def section_urls(titles, base_url):
return dict((title, f'{base_url}#{nodes.make_id(title)}')
for title in titles)
请参阅
help(nodes.make_id)
了解将标题文本转换为 ID 的函数。
让我们测试一下这些功能:
from docutils import core
base_url = "file:demo.html"
sample = """\
Document Title
==============
:docinfo: optional
first section heading
---------------------
first section text
subsection 1.1
..............
subsection text
second section heading
----------------------
second section text
subsection 2.1
..............
subsection text
"""
def demo(fun):
doctree = core.publish_doctree(sample, base_url)
# print(doctree.pformat()) # show the document structure as "pseudo-XML"
titles = fun(doctree)
# print titles
url_dict = section_urls(titles, base_url)
for title, url in url_dict.items():
print(f'{title}: {url}')
print('extract all')
demo(all_section_titles)
print('\nextract top')
demo(top_section_titles)
print('\nextract sub')
demo(sub_section_titles)