Docx 怎么获取文档目录以及 页码

python docx 怎么获取文档目录以及 页码

@Tiaohh

要在Python中使用Aspose.Words库获取Word文档的目录及其页码,您可以按照以下步骤进行操作:

  1. 插入目录:您可以使用DocumentBuilder.insert_table_of_contents方法在文档中插入目录。该方法允许您通过传递特定的字段开关来控制目录的构建和显示方式。

  2. 更新目录:在插入目录后,您需要调用Document.update_fieldsDocument.update_page_layout方法来更新目录。这两个方法必须按顺序调用,以确保目录中的页码正确显示。

以下是一个示例代码,展示了如何插入和更新目录:

import aspose.words as aw

# 创建一个新的文档
doc = aw.Document()
builder = aw.DocumentBuilder(doc)

# 插入一些示例内容
builder.ParagraphFormat.StyleIdentifier = aw.StyleIdentifier.HEADING_1
builder.Writeln("章节 1")
builder.ParagraphFormat.StyleIdentifier = aw.StyleIdentifier.HEADING_2
builder.Writeln("小节 1.1")
builder.ParagraphFormat.StyleIdentifier = aw.StyleIdentifier.HEADING_1
builder.Writeln("章节 2")

# 插入目录
builder.InsertTableOfContents("\\o \"1-3\" \\h \\z \\u")

# 更新目录
doc.UpdateFields()
doc.UpdatePageLayout()

# 保存文档
doc.Save("DocumentWithTOC.docx")

在这个示例中,我们首先创建了一个新的文档并插入了一些带有标题样式的内容。然后,我们插入了一个目录,并通过调用更新方法来确保目录中的页码正确显示。最后,我们将文档保存为DocumentWithTOC.docx

通过这种方式,您可以轻松地在Word文档中获取目录及其对应的页码。

如果您需要更详细的信息或其他功能,请参考Aspose.Words的官方文档。

Sources:
[1]: Working with Table of Contents|Aspose.Words for Python via .NET

怎么按照目录的页码进行切割save新的文件

@Tiaohh 您可以使用以下代码收集内容表数据,然后获取新文档:

doc = aw.Document("input.docx")

toc = []
for field in doc.get_child_nodes(aw.NodeType.FIELD_START, True):
    field = field.as_field_start()
    if field.field_type == aw.fields.FieldType.FIELD_HYPERLINK and "_Toc" in field.get_field().get_field_code():
        title, page = field.get_field().display_result.split('\t')
        toc.append({
            'title': title,
            'page': int(page)
        })

# 根据 TOC 条目提取页面
for i in range(len(toc)):
    start_page = toc[i]['page'] - 1
    end_page = toc[i + 1]['page'] - 1 if i + 1 < len(toc) else doc.page_count

    # 计算要提取的页数
    diff = end_page - start_page

    # 提取并保存页面
    new_doc = doc.extract_pages(start_page, diff)
    new_doc.save(f"output_{start_page}.docx")

不对 比如页面是9 那就是从9页开始切割。目前切割出来的是 目录呢

@Tiaohh 请提供输入文件和预期输出文件。

表目录.docx (41.1 KB)

我需要目录页面进行切割文件。 比如
表1.2.4 基线生命体征定量结果描述(ITT) 就是第7页到第8页进行分割

@Tiaohh 您可以稍稍更改所提供的代码,并按页码或名称剪切页面:

def test_get_pages_by_toc(self) -> None:
    doc = aw.Document("input.docx")
    self.extract_section_by_page(doc, "1.2.4")

def get_toc_information(self, doc: aw.Document) -> list:
    """从文件中提取 TOC 信息。"""
    toc = []
    for field in doc.get_child_nodes(aw.NodeType.FIELD_START, True):
        field = field.as_field_start()
        if field.field_type == aw.fields.FieldType.FIELD_HYPERLINK and "_Toc" in field.get_field().get_field_code():
            title, page = field.get_field().display_result.split('\t')
            toc.append({
                'title': title,
                'page': int(page)
            })
    return toc

def _get_start_end_pages(self, toc: list, index: int, doc: aw.Document) -> tuple:
    """确定章节的起始页和结束页。"""
    start_page = toc[index]['page'] - 1
    next_entry_index = index + 1
    end_page = toc[next_entry_index]['page'] - 1 if next_entry_index < len(toc) else doc.page_count
    return start_page, end_page - start_page

def get_data_by_page_number(self, doc: aw.Document, toc: list, page_number: int) -> tuple:
    """根据页码获取要提取的起始页和页数。"""
    selected_entry = next((entry for entry in toc if entry['page'] <= page_number), None)
    if selected_entry is None:
        print("No TOC entry found for the given page number.")
        return None, None

    index = toc.index(selected_entry)
    return self._get_start_end_pages(toc, index, doc)

def get_data_by_toc_name(self, doc: aw.Document, toc: list, toc_name: str) -> tuple:
    """根据 TOC 名称获取要提取的起始页和页数。"""
    selected_entry = next((entry for entry in toc if toc_name in entry['title']), None)
    if selected_entry is None:
        print("No TOC entry found for the given TOC name.")
        return None, None

    index = toc.index(selected_entry)
    return self._get_start_end_pages(toc, index, doc)

def extract_section_by_page(self, doc: aw.Document, toc_name: str) -> None:
    """根据页码提取文档的某一部分。"""
    toc = self.get_toc_information(doc)
    # start_page, diff = self.get_data_by_page_number(doc, toc, page_number)
    start_page, diff = self.get_data_by_toc_name(doc, toc, toc_name)

    if start_page is not None and diff is not None:
        new_doc = doc.extract_pages(start_page, diff)
        new_doc.save(f"output_{start_page + 1}.docx")

为什么这个文件分割不出来
a.docx (8.8 MB)

@Tiaohh 该文档的前 3 页为 TOC,因此页码与实际页码位置不同。 您可以使用布局收集器获取 TOC 页数,然后计算 TOC 的实际页码。 我修改了代码,以便与文档一起使用,所以你可以把它作为一个起点:

def test_get_pages_by_toc(self):
    doc = aw.Document("input.docx")
    self.extract_section_by_page(doc, "14.1.3.1")

def get_toc_information(self, doc: aw.Document):
    """从文件中提取 TOC 信息。"""
    layout_collector = aw.layout.LayoutCollector(doc)
    toc = []

    # 提取 TOC 中的超链接字段。
    hyperlink_fields = [
        field.as_field_start() for field in doc.get_child_nodes(aw.NodeType.FIELD_START, True)
        if field.as_field_start().field_type == aw.fields.FieldType.FIELD_HYPERLINK
           and "_Toc" in field.as_field_start().get_field().get_field_code()
    ]

    if not hyperlink_fields:
        return toc

    # 处理每个 TOC 条目。
    for field in hyperlink_fields:
        title, page = field.get_field().display_result.split('\t')
        toc.append({'title': title, 'page': int(page)})

    # 确定 TOC 的最后一页。
    end_toc_page = layout_collector.get_start_page_index(hyperlink_fields[-1])

    # 调整页码,以考虑到 TOC 在文件中的位置。
    for entry in toc:
        entry['page'] += end_toc_page - 1

    return toc

def _get_start_end_pages(self, toc: list, index: int, doc: aw.Document):
    """确定章节的起始页和结束页。"""
    start_page = toc[index]['page']
    next_entry_index = index + 1
    end_page = toc[next_entry_index]['page'] if next_entry_index < len(toc) else doc.page_count
    diff = max(1, end_page - start_page)  # 确保至少提取了一页。
    return start_page, diff

def get_data_by_page_number(self, doc: aw.Document, toc: list, page_number: int):
    """根据页码获取起始页和要提取的页数。"""
    selected_entry = next((entry for entry in toc if entry['page'] <= page_number), None)
    if selected_entry is None:
        return None, None

    index = toc.index(selected_entry)
    return self._get_start_end_pages(toc, index, doc)

def get_data_by_toc_name(self, doc: aw.Document, toc: list, toc_name: str):
    """根据 TOC 名称获取起始页和要提取的页数。"""
    selected_entry = next((entry for entry in toc if toc_name in entry['title']), None)
    if selected_entry is None:
        return None, None

    index = toc.index(selected_entry)
    return self._get_start_end_pages(toc, index, doc)

def extract_section_by_page(self, doc: aw.Document, toc_name: str):
    """根据 TOC 名称提取文档的某个部分。"""
    toc = self.get_toc_information(doc)
    if not toc:
        return

    start_page, diff = self.get_data_by_toc_name(doc, toc, toc_name)
    if start_page is None or diff is None:
        return

    new_doc = doc.extract_pages(start_page, diff)
    new_doc.save(f"output_{start_page + 1}.docx")
import os

import aspose.words as aw

lic = aw.License()
lic_path = "../../../Aspose.Total.Product.Family.lic"
lic.set_license(lic_path)
from bs4 import BeautifulSoup


class a:

    def test_get_pages_by_toc(self):
        doc = aw.Document("5610 TFL_word/CN21-7013_TFL_20231215(1).docx")
        self.extract_section_by_page(doc, "14.1.3.1")
    def get_toc_information(self, doc: aw.Document):
        """从文件中提取 TOC 信息。"""
        layout_collector = aw.layout.LayoutCollector(doc)
        toc = []

        # 提取 TOC 中的超链接字段。
        hyperlink_fields = [
            field.as_field_start() for field in doc.get_child_nodes(aw.NodeType.FIELD_START, True)
            if field.as_field_start().field_type == aw.fields.FieldType.FIELD_HYPERLINK
               and "_Toc" in field.as_field_start().get_field().get_field_code()
        ]

        if not hyperlink_fields:
            return toc

        # 处理每个 TOC 条目。
        for field in hyperlink_fields:
            title, page = field.get_field().display_result.split('\t')
            toc.append({'title': title, 'page': int(page)})

        # 确定 TOC 的最后一页。
        end_toc_page = layout_collector.get_start_page_index(hyperlink_fields[-1])

        # 调整页码,以考虑到 TOC 在文件中的位置。
        for entry in toc:
            entry['page'] += end_toc_page - 1

        return toc

    def _get_start_end_pages(self, toc: list, index: int, doc: aw.Document):
        """确定章节的起始页和结束页。"""
        start_page = toc[index]['page']
        next_entry_index = index + 1
        end_page = toc[next_entry_index]['page'] if next_entry_index < len(toc) else doc.page_count
        diff = max(1, end_page - start_page)  # 确保至少提取了一页。
        return start_page, diff

    def get_data_by_page_number(self, doc: aw.Document, toc: list, page_number: int):
        """根据页码获取起始页和要提取的页数。"""
        selected_entry = next((entry for entry in toc if entry['page'] <= page_number), None)
        if selected_entry is None:
            return None, None

        index = toc.index(selected_entry)
        return self._get_start_end_pages(toc, index, doc)

    def get_data_by_toc_name(self, doc: aw.Document, toc: list, toc_name: str):
        """根据 TOC 名称获取起始页和要提取的页数。"""
        selected_entry = next((entry for entry in toc if toc_name in entry['title']), None)
        if selected_entry is None:
            return None, None

        index = toc.index(selected_entry)
        return self._get_start_end_pages(toc, index, doc)

    def extract_section_by_page(self, doc: aw.Document, toc_name: str):
        """根据 TOC 名称提取文档的某个部分。"""
        output_folder = "a"
        if not os.path.exists(output_folder):
            os.makedirs(output_folder)
        toc = self.get_toc_information(doc)
        if not toc:
            return

        start_page, diff = self.get_data_by_toc_name(doc, toc, toc_name)
        if start_page is None or diff is None:
            return

        new_doc = doc.extract_pages(start_page, diff)
        new_file_path = os.path.join(output_folder, f"output_{start_page + 1}.docx")
        new_doc.save(new_file_path)



if __name__ == "__main__":
    A = a()
    A.test_get_pages_by_toc()

还是不对啊 怎么最后分割出来一个文件

@Tiaohh 正如您在之前的消息中所描述的,您需要根据特定名称查找页面,然后将其拆分为文件。此代码获取“14.1.3.1”的页面,然后将这些页面提取到一个包含两个页面的文件中。这种行为并不是什么新鲜事,只是改进了计算。您可以根据需要的其他要求重新进行页面计算。

我不希望这样计算。我需要把这个文件切分

@Tiaohh 要将文档分割成文件,可以使用 extract_pages 并根据需要获取页码。
例如,您已经收集了 TOC 数据,那么您可以根据某些特定的要求筛选出这些数据,然后获取所有这些 TOC 的起始页和总页数信息,并分割您的文档。

怎么做呢 不太理解?????

@Tiaohh 例如,您可以尝试使用 regex 来查找所需的 TOC (在此示例中,我们可以找到介于 14.1、14.2、14.3 等页面之间的页面):

def test_get_pages_by_toc(self):
    doc = aw.Document("input.docx")

    toc = self.get_toc_information(doc, r"^\d+\.\d\s")
    for index in range(0, len(toc)):
        start_page, diff = self._get_start_end_pages(toc, index, doc)
        if start_page is None or diff is None:
            return

        new_doc = doc.extract_pages(start_page, diff)
        new_doc.save(f"output_{start_page + 1}.docx")

def get_toc_information(self, doc: aw.Document, pattern: str):
    """从文件中提取 TOC 信息。"""
    layout_collector = aw.layout.LayoutCollector(doc)
    toc = []

    # 提取 TOC 中的超链接字段。
    hyperlink_fields = [
        field.as_field_start() for field in doc.get_child_nodes(aw.NodeType.FIELD_START, True)
        if field.as_field_start().field_type == aw.fields.FieldType.FIELD_HYPERLINK
           and "_Toc" in field.as_field_start().get_field().get_field_code()
    ]

    if not hyperlink_fields:
        return toc

    # 处理每个 TOC 条目。
    for field in hyperlink_fields:
        title, page = field.get_field().display_result.split('\t')

        # 查找文本中的所有匹配项。
        matches = re.findall(pattern, title)
        if matches:
            toc.append({'title': title, 'page': int(page)})

    # 确定 TOC 的最后一页。
    end_toc_page = layout_collector.get_start_page_index(hyperlink_fields[-1])

    # Adjust page numbers to account for the TOC's position in the document.
    for entry in toc:
        entry['page'] += end_toc_page - 1

    return toc

def _get_start_end_pages(self, toc: list, index: int, doc: aw.Document):
    """确定章节的起始页和结束页。"""
    start_page = toc[index]['page']
    next_entry_index = index + 1
    end_page = toc[next_entry_index]['page'] if next_entry_index < len(toc) else doc.page_count
    diff = max(1, end_page - start_page)  # Ensure at least one page is extracted
    return start_page, diff

此外,您还可以使用代码较少的 Splitter 类来分割文档:Splitter class | Aspose.Words for Python

怎么使用代码较少的 Splitter 类来分割文档呢。以我上传的文件 帮我分割成对应页面范围的文件

@Tiaohh 这取决于您的要求,但您总能从我提供的文档中获得示例。

如果你想简单地按页面分割文档,可以使用下面的代码:

options = aw.lowcode.SplitOptions()
options.split_criteria = aw.lowcode.SplitCriteria.PAGE
aw.lowcode.Splitter.split("input.docx", 'output.docx', options)

例如,按特定风格:

options = aw.lowcode.SplitOptions()
options.split_criteria = aw.lowcode.SplitCriteria.STYLE
options.split_style = "Heading 2"
aw.lowcode.Splitter.split("input.docx", 'output.docx', options)

这里有一个 SplitCriteria 供您使用。

在更复杂的情况下,可以使用上面提供的 doc.extract_pages 方法。例如,分成几页:

doc = aw.Document("input.docx")

# 获取文档的总页数。
page_count = doc.page_count

# 定义每次分割的页数。
pages_per_split = 2

# 循环浏览文件,每两页分割一次。
for i in range(0, page_count, pages_per_split):
    # 计算起始页和结束页索引。
    start_page = i
    end_page = min(i + pages_per_split - 1, page_count - 1)

    # 提取页面。
    extracted_doc = doc.extract_pages(start_page, end_page - start_page + 1)

    extracted_doc.save(f"output_pages_{start_page + 1}_to_{end_page + 1}.docx")