【1902】process_handout_pdf()

python 复制代码
import fitz  # PyMuPDF
import re
from typing import List, Dict, Any
import json

def process_handout_pdf(pdf_path: str, chapter_num: int) -> List[Dict[str, Any]]:
    """
    处理单个handout PDF,提取文字、图像、图表等内容并给它们打标签。
    此函数只负责数据提取和标签生成,不生成幻灯片。
    """
    data = []  # 存储提取的所有数据和标签

    doc = None
    try:
        doc = fitz.open(pdf_path)
    except Exception as e:
        print(f"无法打开PDF: {e}")
        return []

    total_pages = len(doc)
    for page_num in range(total_pages):
        page = doc.load_page(page_num)  # 加载页

        # 1. 提取文字
        text_data = extract_text(page)
        if text_data:
            data.append({
                "type": "text",
                "content": text_data,
                "source": {
                    "pdf_name": pdf_path.split('/')[-1],  # 只取文件名
                    "page": page_num + 1  # 页面编号从1开始
                },
                "content_labels": get_content_labels(text_data)
            })

        # 2. 提取图像
        image_data = extract_images(page)
        for img in image_data:
            data.append({
                "type": "image",
                "content": img,
                "source": {
                    "pdf_name": pdf_path.split('/')[-1],
                    "page": page_num + 1
                },
                "content_labels": get_content_labels(img)
            })

        # 3. 提取图表(如果需要,可以根据图表的特征进行提取,这里假设它是图片)
        chart_data = extract_charts(page)  # 如果有特定方法提取图表,加入此函数
        for chart in chart_data:
            data.append({
                "type": "chart",
                "content": chart,
                "source": {
                    "pdf_name": pdf_path.split('/')[-1],
                    "page": page_num + 1
                },
                "content_labels": get_content_labels(chart)
            })

        # 4. 提取其他元素(例如,表格、公式等)
        other_data = extract_other_elements(page)
        for element in other_data:
            data.append({
                "type": "other",
                "content": element,
                "source": {
                    "pdf_name": pdf_path.split('/')[-1],
                    "page": page_num + 1
                },
                "content_labels": get_content_labels(element)
            })

    # 关闭PDF
    doc.close()

    return data

# ==========================
# 提取具体元素的辅助函数
# ==========================
def extract_text(page: fitz.Page) -> str:
    """
    提取页面上的纯文字内容
    """
    return page.get_text("text")

def extract_images(page: fitz.Page) -> List[str]:
    """
    提取页面上的所有图像,返回图片的URL或数据(在这里模拟为简单描述)
    """
    image_data = []
    images = page.get_images(full=True)
    for img_index, img in enumerate(images):
        # 简单示例:返回每个图片的描述
        image_data.append(f"Image {img_index + 1}")
    return image_data

def extract_charts(page: fitz.Page) -> List[str]:
    """
    提取页面上的图表。此处假设图表以图像形式存储。
    若有其他方式来提取图表,可以在此函数扩展。
    """
    # 这里模拟图表提取,实际可能需要更复杂的图像分析方法
    return extract_images(page)

def extract_other_elements(page: fitz.Page) -> List[str]:
    """
    提取页面上的其他元素,例如表格、公式等。这里假设为文本或图像内容。
    """
    return extract_text(page).split("\n")  # 只是一个简单的拆分作为示例

# ==========================
# 内容标签生成辅助函数
# ==========================
def get_content_labels(content: str) -> List[str]:
    """
    利用LLM或规则,为内容打上3-5个标签(知识点、专有名词等)。
    这里只是模拟示例,实际可以调用LLM来进行识别。
    """
    # 模拟通过 LLM 生成标签:此部分可以通过真正的 LLM 接口来生成
    labels = []

    # 规则判断:例如识别学科、人物、专有名词等(模拟)
    if re.search(r'\bAI\b|\b机器学习\b', content):  # 识别AI或机器学习
        labels.append("机器学习")
    if re.search(r'\b数据科学\b', content):  # 识别数据科学
        labels.append("数据科学")
    if re.search(r'\b图像处理\b', content):  # 识别图像处理
        labels.append("图像处理")
    
    # 添加人物/名词(例如,课程中的人物、模型等)
    if re.search(r'\b(图灵\b|Alan Turing\b)', content):  # 识别图灵
        labels.append("Alan Turing")

    # 模拟一个标签列表返回(根据内容生成标签,具体可根据需求优化)
    if not labels:
        labels = ["通用内容"]  # 没有识别到特定标签时,加个默认标签

    # 返回最多5个标签
    return labels[:5]

# ==========================
# 数据结构存储
# ==========================
def get_structured_data(data: List[Dict[str, Any]]) -> Dict[str, Any]:
    """
    将提取的数据整理成合适的结构,以便后续操作(例如:根据标签对内容进行整合)
    """
    structured_data = {
        "texts": [],
        "images": [],
        "charts": [],
        "others": []
    }

    # 根据类型将数据分配到不同类别
    for item in data:
        if item["type"] == "text":
            structured_data["texts"].append(item)
        elif item["type"] == "image":
            structured_data["images"].append(item)
        elif item["type"] == "chart":
            structured_data["charts"].append(item)
        else:
            structured_data["others"].append(item)

    return structured_data

Dialogue 1

代码解释

提取元素:

process_handout_pdf 会提取 PDF 中的文字、图像、图表以及其他元素。每种提取内容都通过不同的辅助函数处理,如 extract_text 提取文字,extract_images 提取图像,extract_charts 提取图表(在此用图像模拟),extract_other_elements 提取其他内容(如表格、公式等)。

标签生成:

为每个提取的内容(无论是文字、图像还是其他元素)生成两个类型的标签:

来源标签:包括来源的 PDF 文件名和页码。

内容标签:使用简单的正则表达式模拟通过 LLM 提取知识点、人物等标签,实际应用中你可以接入 LLM API 来实现更复杂的标签生成。

每个提取的内容会关联多个标签(最多 5 个),并存储在 content_labels 字段中。

数据结构:

最终生成的数据将被组织成一个字典(structured_data),该字典将不同类型的提取内容(文字、图像、图表、其他元素)分类存储,便于后续处理和分析。

存储和整合:

get_structured_data 函数将数据根据类型整理,并返回最终结构。这将为后续的分析、展示或聚类等任务提供数据支持。

下一步

LLM 接入:你可以根据需要替换 get_content_labels 函数中的标签生成部分,调用实际的 LLM API 来识别更准确的内容标签。

图像和图表的进一步分析:如果图表有结构化数据(如图表表格数据),可以使用 OCR 或图表解析方法提取这些信息,而不仅仅是图片描述。

这样,你就完成了数据提取、标签生成和结构化存储的处理部分。


Dialogue 2

确实,之前的 extract_charts 和 extract_other_elements 函数中有些内容只是伪代码或者假设代码。图表、公式、表格等内容的提取是一个复杂的问题,因为它们通常以不同的方式呈现,尤其是图表可能是图片形式,表格通常是结构化文本或表格对象。

下面是针对 提取图表 和 提取表格 的具体代码实现示例:

1. 提取图表

对于图表,很多情况下,它们是作为图片嵌入在PDF中,因此我们可以通过图像提取来获取图表。下面的代码假设图表以图像形式存在,并使用 fitz(PyMuPDF)提取图像。

python 复制代码
def extract_charts(page: fitz.Page) -> List[str]:
    """
    提取页面上的图表,假设图表是图像格式。
    """
    charts = []
    images = page.get_images(full=True)  # 获取页面上的所有图像
    for img_index, img in enumerate(images):
        xref = img[0]  # 图片的xref
        base_image = fitz.Pixmap(page.doc, xref)  # 使用xref提取图片

        # 可以在这里进行进一步的图像处理,例如将其转换为PNG、JPG等格式并保存
        # 或者你可以选择对图像进行OCR分析,提取图表的结构化数据

        # 将图像作为图表添加到结果列表中
        charts.append(f"Chart {img_index + 1} (image {xref})")

    return charts

2. 提取表格

表格一般是由多行和多列组成的结构化数据,但在 PDF 中,表格通常是通过 Text 内容或者嵌入的表格对象来表示的。通过 fitz 可以提取文本,并通过一定的规则来判断哪些内容属于表格。

这里是一个基本的 提取表格数据 的示例,我们将所有文本提取出来,然后尝试识别以表格形式呈现的内容:

python 复制代码
def extract_table(page: fitz.Page) -> List[Dict[str, Any]]:
    """
    提取页面上的表格数据。假设表格是以文本形式呈现,按照行列对齐。
    使用fitz的get_text方法提取文本。
    """
    table_data = []
    text = page.get_text("text")  # 提取页面的纯文本
    lines = text.split("\n")  # 按行分割文本
    
    # 设定一个简单规则来判断表格的列数和行数(假设表格有固定的列宽)
    # 这里假设表格是通过空格或制表符分隔的
    for line in lines:
        columns = line.split()  # 简单以空格分割列
        if len(columns) > 1:  # 如果列数多于1,认为是表格行
            table_data.append({"columns": columns})
    
    return table_data

3. 提取公式

公式提取比较复杂,尤其是PDF中的公式有时是嵌入的图片,有时是文本形式。下面是一个简化的例子:

python 复制代码
def extract_formulae(page: fitz.Page) -> List[str]:
    """
    提取页面上的公式。假设公式是以图片形式存在,使用get_images()方法提取。
    """
    formulas = []
    images = page.get_images(full=True)
    for img_index, img in enumerate(images):
        xref = img[0]
        base_image = fitz.Pixmap(page.doc, xref)

        # 假设公式是通过图片存储的,可以选择OCR处理这些图片
        # 或者直接将其标记为公式
        formulas.append(f"Formula {img_index + 1} (image {xref})")
    
    return formulas

4. 综合方案

你可以将图表、表格、公式的提取代码整合到一个 extract_other_elements 方法中,根据实际情况返回这些提取结果。比如,提取图表、表格和公式,并将它们存储在一个统一的数据结构中:

python 复制代码
def extract_other_elements(page: fitz.Page) -> List[Dict[str, Any]]:
    """
    提取页面上的其他元素,如图表、公式和表格。
    """
    other_elements = []

    # 提取图表
    charts = extract_charts(page)
    for chart in charts:
        other_elements.append({
            "type": "chart",
            "content": chart
        })

    # 提取表格
    tables = extract_table(page)
    for table in tables:
        other_elements.append({
            "type": "table",
            "content": table
        })

    # 提取公式
    formulae = extract_formulae(page)
    for formula in formulae:
        other_elements.append({
            "type": "formula",
            "content": formula
        })

    return other_elements

总结

图表提取:假设图表是以图片形式嵌入 PDF 中,使用 get_images 提取图片,并将其作为图表处理。

表格提取:提取文本并根据简单的规则分割表格数据。如果有其他复杂的表格格式,可以考虑使用 fitz 提供的 get_text("dict") 方法来提取表格数据。

公式提取:假设公式是图片(这在学术论文中较为常见),同样通过提取图像来获取公式。

这种方法对 图像、文本表格 和 公式 进行了较为简单的处理,但实际应用中,你可能需要更多的优化。例如,可以结合 OCR 技术(如 Tesseract)来对图像中的文本进行识别,以提取更丰富的图表和公式信息。

如果你需要进一步细化图像或表格的处理,或者希望将公式从文本中提取出来,你可以考虑结合图像识别和数学公式解析库。


Dialogue 3

python 复制代码
import os
import fitz  # PyMuPDF
from typing import List, Dict, Any
import re

# 设置存储图像的目录
IMAGE_DIR = "extracted_images"

def extract_text(page: fitz.Page) -> str:
    """
    提取页面上的纯文字内容
    """
    return page.get_text("text")  # 获取纯文本

def extract_images(page: fitz.Page) -> List[str]:
    """
    提取页面上的所有图像,返回图片的描述。
    """
    image_data = []
    images = page.get_images(full=True)
    for img_index, img in enumerate(images):
        xref = img[0]  # 图像的xref
        base_image = fitz.Pixmap(page.doc, xref)  # 使用xref提取图片

        # 检查图像是否为灰度图,如果是,转换为RGB
        if base_image.n < 4:  # 如果是灰度图或调色板图像
            base_image = fitz.Pixmap(fitz.csRGB, base_image)  # 转换为RGB模式

        # 确保图像目录存在
        if not os.path.exists(IMAGE_DIR):
            os.makedirs(IMAGE_DIR)

        # 定义图像保存路径
        image_path = os.path.join(IMAGE_DIR, f"image_{xref}.png")

        # 将图像保存为PNG格式
        base_image.save(image_path)  # 保存为PNG文件

        # 将图像路径作为图像记录添加到列表
        image_data.append({
            "type": "image",
            "content": {
                "image_path": image_path,  # 图像文件路径
                "xref": xref  # 图像的xref
            }
        })

        # 清理内存中的图像对象
        base_image = None

    return image_data

def extract_charts(page: fitz.Page, chapter_num: int) -> List[Dict[str, Any]]:
    """
    提取页面上的图表,假设图表是图像格式。
    将图像转换为PNG并保存到文件系统中,同时返回图像路径。
    """
    charts = []
    images = page.get_images(full=True)  # 获取页面上的所有图像

    for img_index, img in enumerate(images):
        xref = img[0]  # 图像的xref
        base_image = fitz.Pixmap(page.doc, xref)  # 使用xref提取图片

        # 检查图像是否为灰度图,如果是,转换为RGB
        if base_image.n < 4:  # 如果是灰度图或调色板图像
            base_image = fitz.Pixmap(fitz.csRGB, base_image)  # 转换为RGB模式

        # 确保图像目录存在
        if not os.path.exists(IMAGE_DIR):
            os.makedirs(IMAGE_DIR)

        # 定义图像保存路径
        image_path = os.path.join(IMAGE_DIR, f"chart_{chapter_num}_{img_index + 1}.png")

        # 将图像保存为PNG格式
        base_image.save(image_path)  # 保存为PNG文件

        # 将图像路径作为图表记录添加到结果列表
        charts.append({
            "type": "chart",
            "content": {
                "image_path": image_path,  # 图像文件路径
                "xref": xref  # 图像的xref
            },
            "source": {
                "chapter": chapter_num,
                "image_index": img_index + 1
            }
        })

        # 清理内存中的图像对象
        base_image = None

    return charts

def process_handout_pdf(pdf_path: str, chapter_num: int) -> List[Dict[str, Any]]:
    """
    处理handout PDF,提取文字、图像、图表,并保存图像到文件系统。
    """
    data = []  # 存储提取的所有数据和标签

    doc = None
    try:
        doc = fitz.open(pdf_path)
    except Exception as e:
        print(f"无法打开PDF: {e}")
        return []

    total_pages = len(doc)
    for page_num in range(total_pages):
        page = doc.load_page(page_num)  # 加载页

        # 1. 提取文字
        text_data = extract_text(page)
        if text_data:
            data.append({
                "type": "text",
                "content": text_data,
                "source": {
                    "pdf_name": pdf_path.split('/')[-1],  # 只取文件名
                    "page": page_num + 1  # 页面编号从1开始
                }
            })

        # 2. 提取图像
        image_data = extract_images(page)
        for img in image_data:
            data.append(img)

        # 3. 提取图表
        chart_data = extract_charts(page, chapter_num)
        for chart in chart_data:
            data.append(chart)

    # 关闭PDF
    doc.close()

    return data

# 示例:调用提取图表、图像、文字的函数
def main():
    pdf_path = "path_to_your_pdf.pdf"  # 请替换成你的 PDF 文件路径
    chapter_num = 1  # 章节号
    extracted_data = process_handout_pdf(pdf_path, chapter_num)

    # 打印提取的数据
    for item in extracted_data:
        if item["type"] == "text":
            print(f"文字内容:\n{item['content']}")
        elif item["type"] == "image":
            print(f"图像保存路径: {item['content']['image_path']}")
        elif item["type"] == "chart":
            print(f"图表图像保存路径: {item['content']['image_path']}")

if __name__ == "__main__":
    main()

代码说明

提取文字:

使用 extract_text(page) 提取页面上的纯文本内容。

使用 page.get_text("text") 提取每页的文字信息,返回一个文本字符串。

提取图像:

使用 extract_images(page) 提取页面上的所有图像。每个图像都转换为 PNG 格式并保存在本地文件系统中。

图像路径和 xref(图片标识符)被存储在返回的数据结构中,以便后续使用。

提取图表:

使用 extract_charts(page, chapter_num) 提取页面上的图表,并假设它们是图像。图像转换为 PNG 格式并保存到文件系统中。

图表也被保存为图像路径,并返回给调用者。

数据结构:

提取的每个元素(文字、图像、图表)都以字典的形式存储,包含 type(内容类型)、content(具体内容,如文字或图像路径)以及 source(来源,包含文件名、页码或章节号)。

图像和图表存储:

图像和图表被保存在 extracted_images 目录中,文件名根据图像的 xref 或章节号来生成(例如 image_1.png 或 chart_1_1.png)。

图像的路径被添加到返回的字典中,之后可以进一步使用或将其存储到数据库中(如果需要)。

主函数 main():

示例中,我们调用 process_handout_pdf 来提取 PDF 中的文字、图像和图表,并打印结果。

运行方式

替换 pdf_path 为你需要提取数据的 PDF 文件路径。

调用 process_handout_pdf 函数,提取 PDF 中的文字、图像和图表。

结果将被打印出来,包括每个提取内容的类型(文字、图像、图表)和相应的保存路径或内容。

改进思路

图像压缩与优化:为了节省存储空间,你可以考虑将图像保存时进行压缩。可以使用 PIL 库来调整图像质量或大小。

OCR:如果图表包含文本内容,且你希望从图像中提取文字,可以集成 OCR 库(如 Tesseract)来进行图像文字识别。

更多提取内容类型:如果 PDF 中包含公式、表格或其他元素,你可以在 extract_other_elements 函数中扩展这些提取方法。

这个版本的代码应该能够满足你提取文字、图像、图表,并将它们保存到本地文件系统中的需求。


Dialogue 4

page.get_text("text") # 获取纯文本////一行代码就能搞定吗?

是的,page.get_text("text") 这行代码实际上已经是非常高效的文本提取方式,它会提取 PDF 页面的纯文本内容(包括所有段落、行、单词等)。这个方法会将 PDF 页面的文本按行解析并返回一个字符串。

但是,要注意以下几点:

page.get_text("text") 的工作原理

  • get_text("text") 方法通过解析 PDF 文件中的文本对象(如字体、大小、位置等信息)来提取文本。
  • 它返回的是一个包含页面所有文本内容的单个字符串,其中包括按行分割的文本内容。

简单的示例

python 复制代码
import fitz  # PyMuPDF

def extract_text(page):
    text = page.get_text("text")
    return text

# 示例调用
doc = fitz.open("path_to_pdf.pdf")
page = doc.load_page(0)  # 加载第一页
text = extract_text(page)
print(text)  # 打印提取的文本内容

为什么 get_text("text") 是足够的:

  1. 快速提取文本

    • 这是最常用且高效的提取方法,适用于大部分需要提取页面内容的场景。它能够返回 PDF 页面中的所有可见文本。
  2. 简单易用

    • 只需一行代码 page.get_text("text") 就能获取整个页面的文本内容,避免了手动逐行提取或计算布局的问题。

可能的局限性

  1. 格式丢失

    • 虽然该方法提取了文本内容,但它会丢失原始 PDF 中的布局、字体、颜色等信息。所有的文本都被视作简单的行内容,无法保留表格、列或页面的排版样式。
  2. 复杂 PDF 文件

    • 对于一些复杂的 PDF 文件,特别是那些有非常复杂的排版、图像或自定义字体的文件,get_text("text") 可能无法完美提取所有内容。比如,如果文本被嵌入在图像或特殊对象中,get_text("text") 无法识别这些内容。
  3. 文本提取精度

    • 有时如果文本在 PDF 中按非标准方式编码(例如使用图像嵌入或某些字体压缩技术),get_text 提取的文本可能会存在乱码或错误的情况。

其他选项

如果你需要更精确的控制文本提取,或者希望保留更多的排版信息,可以使用其他参数或方法:

  • get_text("dict"):返回一个包含详细信息的字典,其中包括文本块、单词、字体、颜色等。这对于处理需要保留排版或结构的情况非常有用。
python 复制代码
# 获取更详细的文本信息(包括字体、位置等)
text_dict = page.get_text("dict")
print(text_dict)
  • get_text("html"):返回 HTML 格式的文本内容,包括标签和其他排版信息,适合将 PDF 转换为网页格式。

总结

对于大多数场景,page.get_text("text") 这行代码确实已经足够处理大部分文本提取任务,并且是非常简洁有效的方式。只有在需要保留更复杂的格式或信息时,才可能需要使用其他更高级的选项(如 "dict""html")。

相关推荐
FIT2CLOUD飞致云4 小时前
赛道第一!1Panel成功入选Gitee 2025年度开源项目
服务器·ai·开源·1panel
玖釉-4 小时前
深入浅出:渲染管线中的抗锯齿技术全景解析
c++·windows·图形渲染
yanlou2334 小时前
[C++/Linux HTTP项目] HTTP服务器基于muduo高性能服务器搭载【深入详解】
运维·服务器·http·muduo库·http高性能服务器
天空属于哈夫克34 小时前
企微第三方 RPA API:非官方接口与官方接口的差异解析及选型建议
运维·服务器
niceffking4 小时前
linux 信号内核模型
linux·运维·服务器
残梦53144 小时前
Qt6.9.1起一个图片服务器(支持前端跨域请求,不支持上传,可扩展)
运维·服务器·开发语言·c++·qt
醒过来摸鱼5 小时前
Redis 服务器线程与事件循环解析
服务器·数据库·redis
hweiyu005 小时前
Linux 命令:paste
linux·运维·服务器
Whoami!5 小时前
⓫⁄₈ ⟦ OSCP ⬖ 研记 ⟧ Windows权限提升 ➱ 滥用Windows服务提权(下)
windows·网络安全·信息安全·powerup.ps1
移动云开发者联盟5 小时前
一键部署!移动云全面上线Clawdbot
运维·服务器·负载均衡