Python实现word文档内容智能提取以及合成

2025-04-20 16:50

本文主要是介绍Python实现word文档内容智能提取以及合成,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Python实现word文档内容智能提取以及合成》这篇文章主要为大家详细介绍了如何使用Python实现从10个左右的docx文档中抽取内容,再调整语言风格后生成新的文档,感兴趣的小伙伴可以了解一下...

如何从10个左右的docx文档中抽取内容,生成新的文档,抽取内容包括源文档的文字内容、图片、表格、公式等,以及目标文档的样式排版、字体、格式,还有目标文档的语言风格、用词规范、文法习惯等等。这是一个相当复杂的需求,因为它不仅涉及内容提取,还涉及深度格式化和风格模仿。完全自动化的完美解决方案难度极高,特别是对于复杂的公式和微妙的语言风格。

一个务实的方案是采用 自动化 + 人工辅助 的混合策略。以下是详细的思路、技术路径、方法和步骤:

核心思路

内容提取 (自动化为主): 使用编程方式从源 DOCX 文件中提取所需的核心内容(文字、图片、表格、公式的某种表示)。

样式应用 (自动化): 基于一个定义了目标样式、排版、字体等的 模板文档,将提取的内容插入新文档,并应用模板中定义的样式。

语言风格调整 (自动化辅助 + 人工): 利用大型语言模型 (LLM) 或自然语言处理 (NLP) 技术对提取的文本进行初步的风格、用词和文法调整,然后进行人工审阅和精修。

复杂元素处理 (人工为主): 对于难以自动处理的元素(如复杂公式、特定排版),进行人工调整。

技术路径

主要工具: Python 编程语言

核心库:

  • python-docx: 用于读取和写入 DOCX 文件(文本、表格、图片、基本样式应用)。
  • (可选) 用于公式处理: 可能需要解析 DOCX 的底层 XML (OOXML),或者寻找专门处理 MathML/OMML 的库(这部分比较困难),或者将公式提取为图片。
  • (可选) 用于图片处理: Pillow (PIL Fork) 可能需要用于处理图片。
  • (可选) 用于语言风格调整: 调用大型语言模型 API (如 OpenAI GPT 系列、Google Gemini、或其他类似服务)。

辅助工具:

  • Microsoft Word: 用于创建模板文档、最终审阅和调整。
  • XML 编辑器 (可选): 用于深入分析 DOCX 内部结构(特别是公式)。

实现步骤

阶段一:准备工作

1.创建目标模板文档 (template.docx):

  • 在 Word 中创建一个新文档。
  • 定义样式: 精心设置所有需要的样式(标题 1、标题 2、正文、引用、列表、表格样式等),包括字体、字号、颜色、段落间距、缩进等。确保样式名称清晰易懂(例如 TargetHeading1, TargetBodyText, TargetTableStyle)。
  • 设置页面布局: 页边距、纸张大小、页眉页脚等。
  • 保存: 将此文档保存为 template.docx。这将是所有新生成文档的基础。

2.明确提取规则:

关键: 你需要非常清楚地定义 哪些 内容需要从每个源文档中提取出来。规则可以基于:

  • 特定标题: “提取 ‘第三章 方法’ 下的所有内容”。
  • 特定样式: “提取所有应用了 ‘源文档重点’ 样式的内容”。
  • 关键词/标记: “提取包含 ‘[EXTRACT]’ 标记的段落”。
  • 结构位置: “提取每个文档的第二个表格”。
  • 人工指定: (最灵活但最慢) 手动在源文档中标记要提取的内容(例如使用 Word 的批注功能或特定高亮颜色),然后让脚本识别这些标记。
  • 文档化规则: 将这些规则清晰地记录下来,以便编写脚本。

3.设置开发环境:

安装 Python。

使用 pip 安装必要的库:

pip install python-docx Pillow requests # 如果需要调用 LLM API
# 可能需要其他库,取决于具体实现

(可选) 获取 LLM API 密钥。

阶段二:内容提取 (Python 脚本)

import os
from docx import Document
from docx.shared import Inches
# 可能需要导入其他模块,如处理 XML 或调用 API

# --- 配置 ---
SOURCE_DOCS_DIR = 'files/transform/docx/source_documents'
TARGET_TEMPLATE = 'files/transform/docx/template.docx'
OUTPUT_DOC_PATH = 'files/transform/docx/generated_document.docx'
EXTRACTION_RULES = { # 示例规则,需要根据你的实际情况修改
    'source_doc_1.docx': {'heading_start': 'Chapter 3', 'heading_end': 'Chapter 4'},
    'source_doc_2.docx': {'style_name': 'SourceHighlight'},
    # ... 其他文档的规则
}

# --- 辅助函数 (示例) ---
def should_extract_paragraph(paragraph, rules):
    # 实现基于规则判断段落是否应该提取的逻辑
    # 例如:检查段落文本是否匹配、样式是否匹配等
    # 返回 True 或 False
    # (这部分逻辑需要根据你的具体规则编写)
    style_name = paragraph.style.name
    text = paragraph.text.strip()
    # 示例:基于样式的简单规则
    if 'style_name' in rules and style_name == rules['style_name']:
        return True
    # 示例:基于起始标题的简单规则(需要状态管理)
    # if 'heading_start' in rules ... (需要更复杂的逻辑来跟踪当前章节)
    return False # 默认不提取

def extract_content_from_doc(source_path, rules):
    """从单个源文档提取内容"""
    extracted_elements = []
    try:
        source_doc = Document(source_path)
        # 标记是否处于提取区域(例如,在特定章节之间)
        in_extraction_zone = False # 需要根据规则调整初始状态

        for element in source_doc.element.body:
            # 处理不同类型的元素:段落、表格等
            if element.tag.endswith('p'): # 是段落
                paragraph = docx.text.paragraph.Paragraph(element, source_doc)

                # --- 核心提取逻辑 ---
                # 这里需要根据你的 EXTRACTION_RULES 实现复杂的判断逻辑
                # 例如,判断是否遇到起始标题,是否遇到结束标题,段落样式是否匹配等
                # 这是一个简化的示例,实际可能需要更精细的状态管理
                if 'heading_start' in rules and paragraph.style.name.startswith('Heading') and rules['heading_start'] in paragraph.text:
                    in_extraction_zone = True
                    continue # 不提取起始标题本身?看需求
                if 'heading_end' in rules and paragraph.style.name.startswith('Heading') and rules['heading_end'] in paragraph.text:
                    in_extraction_zone = False
                    continue # 到达结束标题,停止提取

                if in_extraction_zone or should_extract_paragraph(paragraph, rules):
                     # 提取文本内容
                    text_content = paragraph.text
                     # 尝试提取基本格式(粗体、斜体) - 比较复杂,可能需要遍历 runs
                    # TODO: 提取图片 (需要检查段落中的 inline_shapes 或 runs 中的 drawing)
                    # TODO: 提取公式 (极具挑战性,见下文讨论)
                    extracted_elements.append({'type': 'paragraph', 'text': text_content, 'style': paragraph.style.name}) # 可以携带源样式名供参考

            elif element.tag.endswith('tbl'): # 是表格
                table = docx.table.Table(element, source_doc)
                # --- 提取表格 ---
                # TODO: 实现表格提取逻辑,可能需要检查是否在提取区域内
                # if in_extraction_zone or table_should_be_extracted(table, rules):
                table_data = []
                for row in table.rows:
                    row_data = [cell.text for cell in row.cells]
                    table_data.append(row_data)
                extracted_elements.append({'type': 'table', 'data': table_data})

            # --- 处理图片 ---
            # 查找段落内的图片 (inline_shapes)
            # paragraph = docx.text.paragraph.Paragraph(element, source_doc) # Re-get paragraph object if needed
            # for run in paragraph.runs:
            #     if run.element.xpath('.//wp:inline | .//wp:anchor'): # Check for drawings
            #         # This part is complex: need to get image data (rId) and relate it back
            #         # to the actual image part in the docx package.
            #         # python-docx can extract images, but associating them perfectly
            #         # with their original position during extraction requires care.
            #         # Placeholder:
            #         # image_data = get_image_data(run, source_doc)
            #         # if image_data:
            #         #    extracted_elements.append({'type': 'image', 'data': image_data, 'filename': f'img_{len(extracted_elements)}.png'})
            pass # Placeholder for image extraction logic

    except Exception as e:
        print(f"Error processing {source_path}: {e}")
    return extracted_elements

# --- 主流程 ---
all_extracted_content = []
source_files = [f for f in os.listdir(SOURCE_DOCS_DIR) if f.endswith('.docx')]

for filename in source_files:
    source_path = os.path.join(SOURCE_DOCS_DIR, filename)
    rules = EXTRACTION_RULES.get(filename, {}) # 获取该文件的提取规则
    if rules: # 只处理定义了规则的文件
        print(f"Extracting from: {filename}")
        content = extract_content_from_doc(source_pathandroid, rules)
        all_extracted_content.extend(content)
    else:
        print(f"Skipping {filename}, no rules defined.")

print(f"Total elements extracted: {len(all_extracted_content)}")

阶段三:语言风格调整 (可选, Python + LLM API)

# --- ---
import requests
import json

# --- 配置 LLM ---
LLM_API_URL = "YOUR_LLM_API_ENDPOINT" # e.g., OpenAI API URL
LLM_API_KEY = "YOUR_LLM_API_KEY"
LLM_PROMPT_TEMPLATE = """
请根据以下要求,改写这段文字:
目标语言风格:[在此处详细描述,例如:正式、客观、简洁]
用词规范:[在此处列出规范,例如:使用“用户”而非“客户”,避免使用缩写]
文法习惯:[在此处描述,例如:多使用主动语态,句子长度适中]
目标受众:[描述目标读者]
编程
原文:
"{text}"

改写后的文字:
"""

def adapt_text_style(text):
    """使用 LLM API 调整文本风格"""
    if not text.strip():
        return text # 跳过空文本

    prompt = LLM_PROMPT_TEMPLATE.format(text=text)
    headers = {
        "Authorization": f"Bearer {LLM_API_KEY}",
        "Content-Type": "application/json",
    }
    data = {
        "model": "gpt-4", # 或你使用的模型
        "prompt": prompt,
        "max_tokens": 1024, # 根据需要调整
        "temperature": 0.5, # 控制创造性,较低值更保守
    }
    try:
        response = requests.post(LLM_API_URL, headers=headers, json=data)
        response.raise_for_status() # 检查 HTTP 错误
        result = response.json()
        # 解析 LLM 返回的结果,注意不同 API 的格式可能不同
        rewritten_text = result['choices'][0]['text'].strip() # 示例路径
        print(f"Original: {text[:50]}... | Rewritten: {rewritten_text[:50]}...")
        return rewritten_text
    except requests.exceptions.RequestException as e:
        print(f"Error calling LLM API: {e}")
        return text # 出错时返回原文
    except (KeyError, IndexError) as e:
        print(f"Error parsing LLM response: {e} - Response: {response.text}")
        return text # 出错时返回原文

# --- 应用风格调整 ---
adjusted_content = []
for element in all_extracted_content:
    if element['type'] == 'paragraph':
        # --- 调用 LLM API ---
        # adjusted_text = adapt_text_style(element['text'])
        # element['text'] = adjusted_text # 更新文本
        # --- 或者先不调用,等生成后再处理 ---
        adjusted_content.append(element)
    elif element['type'] == 'table':
         # 表格内容也可以逐个单元格处理,但可能效果不佳或成本高
         # 更好的方法可能是将表格内容整理成文本描述给 LLM,或者人工处理
         adjusted_contentphp.append(element)
    elif element['type'] == 'image':
         # 图片无法直接处理
         adjusted_content.append(element)
    # 处理其他类型...

# --- (接续到下一阶段:文档生成) ---

阶段四:生成目标文档 (Python 脚本)

# --- (续上) ---

# --- 创建目标文档 (基于模板) ---
try:
    target_doc = Document(TARGET_TEMPLATE)
except Exception as e:
    print(f"Error loading template {TARGET_TEMPLATE}: {e}")
    # 可以考虑创建一个空文档作为后备
    # target_doc = Document()
    exit()


# --- 填充内容并应用样式 ---
for element in adjusted_content: # 使用调整后的内容,或者原始提取内容
    if element['type'] == 'paragraph':
        text = element['text']
        # --- 核心:应用模板中定义的样式 ---
        # 简单方式:所有段落应用默认正文样式
        # target_doc.add_paragraph(text, style='TargetBodyText') # 假设模板中有此样式

        # 复杂方式:根据源文档信息或内容判断应用哪个目标样式
        # 示例:如果源样式是 Heading 1,应用 TargetHeadiwww.chinasem.cnng1
        source_style = element.get('style', '') # 获取源样式名(如果提取时保存了)
        if source_style.startswith('Heading 1'):
             target_doc.add_paragraph(text, style='TargetHeading1') # 假设模板中有此样式
        elif source_style.startswith('Heading 2'):
             target_doc.add_paragraph(text, style='TargetHeading2')
        # ... 其他样式映射规则
        else:
             target_doc.add_paragraph(text, style='TargetBodyText') # 默认样式

    elif element['type'] == 'table':
        table_data = element['data']
        if table_data:
            # 创建表格
            num_rows = len(table_data)
            num_cols = len(table_data[0]) if num_rows > 0 else 0
            if num_rows > 0 and num_cols > 0:
                # --- 应用模板中定义的表格样式 ---
                table = target_doc.add_table(rows=num_rows, cols=num_cols, style='TargetTableStyle') # 假设模板中有此表格样式
                # 填充数据
                for i, row_data in enumerate(table_data):
                    forChina编程 j, cell_text in enumerate(row_data):
                        # 防止列数不匹配错误
                        if j < len(table.rows[i].cells):
                            table.rows[i].cells[j].text = cell_text
                # 可以添加更多表格格式化代码,如设置列宽等

    elif element['type'] == 'image':
        # --- 添加图片 ---
        # image_data = element['data']
        # image_filename = element['filename']
        # # 需要将 image_data 保存为临时文件或使用 BytesIO
        # from io import BytesIO
        # image_stream = BytesIO(image_data)
        # try:
        #    target_doc.add_picture(image_stream, width=Inches(4.0)) # 调整宽度
        # except Exception as e:
        #    print(f"Error adding image {image_filename}: {e}")
        pass # Placeholder for image insertion

    # --- 处理公式 (挑战) ---
    # 如果公式被提取为图片:
    #   elif element['type'] == 'formula_image':
    #       # 添加图片...
    # 如果公式被提取为 MathML/OMML (XML 字符串):
    #   elif element['type'] == 'formula_mathml':
    #       # 使用 python-docx 直接插入 MathML 很困难
    #       # 可能需要直接操作 OOXML (非常复杂)
    #       # 或者,在段落中插入一个占位符 "[FORMULA]",然后手动替换
    #       target_doc.add_paragraph(f"[FORMULA: {element['id']}]", style='TargetBodyText')
    # 如果公式被提取为纯文本近似值:
    #   elif element['type'] == 'formula_text':
    #       target_doc.add_paragraph(element['text'], style='FormulaStyle') # 可能需要特殊样式

# --- 保存最终文档 ---
try:
    target_doc.save(OUTPUT_DOC_PATH)
    print(f"Document successfully generated: {OUTPUT_DOC_PATH}")
except Exception as e:
    print(f"Error saving document: {e}")

阶段五:人工审阅与精修

1.打开生成的文档 (generated_document.docx)。

2.检查整体结构和内容完整性: 是否所有需要的内容都被提取并放置在正确的位置?

3.检查样式和格式:

  • 所有文本是否应用了正确的模板样式?
  • 字体、字号、间距是否符合要求?
  • 表格样式是否正确?列宽、对齐是否需要调整?
  • 图片位置和大小是否合适?

4.检查语言风格和规范:

  • 通读文本,检查语气、用词是否符合目标要求。
  • 修正 LLM 可能产生的错误或不自然的表达。
  • 确保术语统一。
  • 进行拼写和语法检查。

5.处理复杂元素:

公式: 这是最可能需要手动操作的地方。如果脚本插入了占位符,你需要手动将源文档中的公式复制粘贴过来,或者使用 Word 的公式编辑器重新创建它们。确保公式的编号和引用正确。

特殊排版: 检查是否有需要特殊布局(如图文混排、分栏等)的地方,并手动调整。

6.最终定稿: 保存修改后的文档。

关于公式处理的挑战与策略

难点: DOCX 中的公式通常使用 OMML (Office Math Markup Language) 存储,嵌套在复杂的 XML 结构中。python-docx 对此支持有限。

策略:

  • 提取为图片 (最可行): 尝试在提取阶段将公式渲染或截图为图片。这会丢失编辑能力,但能保证视觉效果。实现起来也有难度,可能需要借助其他工具或库(如 docx2python 库可能提供一些帮助,或者需要分析 OOXML 找到图片表示)。
  • 提取为 MathML/OMML (复杂): 解析 OOXML,提取公式的 XML 片段。但 python-docx 无法直接将这些 XML 重新插入并渲染为公式。需要非常底层的 OOXML 操作。
  • 提取为近似文本 (简单但损失精度): python-docx 读取包含公式的段落 text 属性时,有时会得到一个纯文本的近似表示。这对于简单公式可能够用,但复杂公式会完全失真。
  • 手动处理 (最可靠): 在脚本中识别出公式位置,插入占位符,然后在人工审阅阶段手动复制/创建公式。

总结

这是一个多阶段、结合自动化和人工的过程。

自动化强项: 重复性的内容提取、基于模板的样式应用、初步的文本风格转换(使用 LLM)。

人工介入点: 定义精确的提取规则、处理复杂公式、精调语言风格和术语、最终的格式微调和质量检查。

投入时间最多的部分将是 编写和调试提取逻辑 以及 最终的人工审阅和修正。务必从少量文档和简单规则开始,逐步迭代和完善你的脚本。

以上就是Python实现word文档内容智能提取以及合成的详细内容,更多关于Python word文档内容提取与合成的资料请关注China编程(www.chinasem.cn)其它相关文章!

这篇关于Python实现word文档内容智能提取以及合成的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1154293

相关文章

python中各种常见文件的读写操作与类型转换详细指南

《python中各种常见文件的读写操作与类型转换详细指南》这篇文章主要为大家详细介绍了python中各种常见文件(txt,xls,csv,sql,二进制文件)的读写操作与类型转换,感兴趣的小伙伴可以跟... 目录1.文件txt读写标准用法1.1写入文件1.2读取文件2. 二进制文件读取3. 大文件读取3.1

使用Python实现一个优雅的异步定时器

《使用Python实现一个优雅的异步定时器》在Python中实现定时器功能是一个常见需求,尤其是在需要周期性执行任务的场景下,本文给大家介绍了基于asyncio和threading模块,可扩展的异步定... 目录需求背景代码1. 单例事件循环的实现2. 事件循环的运行与关闭3. 定时器核心逻辑4. 启动与停

基于Python实现读取嵌套压缩包下文件的方法

《基于Python实现读取嵌套压缩包下文件的方法》工作中遇到的问题,需要用Python实现嵌套压缩包下文件读取,本文给大家介绍了详细的解决方法,并有相关的代码示例供大家参考,需要的朋友可以参考下... 目录思路完整代码代码优化思路打开外层zip压缩包并遍历文件:使用with zipfile.ZipFil

Python处理函数调用超时的四种方法

《Python处理函数调用超时的四种方法》在实际开发过程中,我们可能会遇到一些场景,需要对函数的执行时间进行限制,例如,当一个函数执行时间过长时,可能会导致程序卡顿、资源占用过高,因此,在某些情况下,... 目录前言func-timeout1. 安装 func-timeout2. 基本用法自定义进程subp

Python结合PyWebView库打造跨平台桌面应用

《Python结合PyWebView库打造跨平台桌面应用》随着Web技术的发展,将HTML/CSS/JavaScript与Python结合构建桌面应用成为可能,本文将系统讲解如何使用PyWebView... 目录一、技术原理与优势分析1.1 架构原理1.2 核心优势二、开发环境搭建2.1 安装依赖2.2 验

C#实现将Excel表格转换为图片(JPG/ PNG)

《C#实现将Excel表格转换为图片(JPG/PNG)》Excel表格可能会因为不同设备或字体缺失等问题,导致格式错乱或数据显示异常,转换为图片后,能确保数据的排版等保持一致,下面我们看看如何使用C... 目录通过C# 转换Excel工作表到图片通过C# 转换指定单元格区域到图片知识扩展C# 将 Excel

基于Java实现回调监听工具类

《基于Java实现回调监听工具类》这篇文章主要为大家详细介绍了如何基于Java实现一个回调监听工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录监听接口类 Listenable实际用法打印结果首先,会用到 函数式接口 Consumer, 通过这个可以解耦回调方法,下面先写一个

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

Qt中QGroupBox控件的实现

《Qt中QGroupBox控件的实现》QGroupBox是Qt框架中一个非常有用的控件,它主要用于组织和管理一组相关的控件,本文主要介绍了Qt中QGroupBox控件的实现,具有一定的参考价值,感兴趣... 目录引言一、基本属性二、常用方法2.1 构造函数 2.2 设置标题2.3 设置复选框模式2.4 是否

一文详解如何在Python中从字符串中提取部分内容

《一文详解如何在Python中从字符串中提取部分内容》:本文主要介绍如何在Python中从字符串中提取部分内容的相关资料,包括使用正则表达式、Pyparsing库、AST(抽象语法树)、字符串操作... 目录前言解决方案方法一:使用正则表达式方法二:使用 Pyparsing方法三:使用 AST方法四:使用字