获取PDF中的布局信息——如何获取段落

news2024/10/7 10:20:55

  PDF解析是极其复杂的问题。不可能靠一个工具解决全部问题,尤其是五花八门,格式不统一的PDF文件。除非有钞能力。如果没有那就看看可以分为哪些问题。

  提取文本内容,提取表格内容,提取图片。我认为这些应该是分开做的事情。python有一些组件,是有专长的。

  问题分解以后,最重要的一个事情是,版面分析。怎么确定边界,就是哪一块是什么内容?是正文,还是表格,还是图片?

  文本、图片及形状涵盖了常见的PDF元素,本文介绍利用PyMuPDF提取这些页面元素,及其基本数据结构。本文会提供可运行的代码!

一、技术选型 PyMuPDF

PyMuPDFTextpage对象提供的extractDICT()extractRAWDICT()用以获取页面中的所有文本和图片(内容、位置、属性),基本数据结构如下:

看到这里,有分类,有位置信息。

二、代码演示

2.1 安装

pip install PyMuPDF

2.2 demo代码 

import fitz  # PyMuPDF

def extract_text_blocks(pdf_path):
    # 打开 PDF 文件
    pdf_document = fitz.open(pdf_path)
    
    # 存储文本块和行块信息
    text_blocks = []
    line_blocks = []
    
    # 遍历 PDF 中的每一页
    for page_number in range(len(pdf_document)):
        page = pdf_document.load_page(page_number)
        
        # 获取文本块和行块信息
        blocks = page.get_text("dict")["blocks"]
        for b in blocks:
            for l in b["lines"]:
                line_blocks.append({
                    "line": l["spans"],
                    "bbox": l["bbox"],
                    "height": l["bbox"][3] - l["bbox"][1]  # 计算行块的高度
                })
            text_blocks.append({
                "block": b["lines"],
                "bbox": b["bbox"]
            })
    
    # 关闭 PDF 文件
    pdf_document.close()
    
    return text_blocks, line_blocks

# 示例用法
pdf_path = "D:\\angus\\py\\困难pdf节选西藏奇正2022.pdf"
text_blocks, line_blocks = extract_text_blocks(pdf_path)

# 打印提取的文本块信息
for index, block in enumerate(text_blocks):
    print(f"Text Block {index + 1}:")
    for line_index, line in enumerate(block["block"]):
        print(f"  Line {line_index + 1}: '{line['spans']}' at position {block['bbox']}")

# 打印提取的行块信息
for index, line in enumerate(line_blocks):
    print(f"Line {index + 1}: '{line['line']}' at position {line['bbox']}, height={line['height']}")

三、效果展示

3.1 原文PDF内容

 3.2 解析后得到的结果

 3.3 分析原文和结果

对比输出的结果和原文。我们可以发现,我们拿到了行的数据,也拿到了段落的数据。上述的代码中已经给我们分好了块!这样解可以区分段落了。

3.4 获取更多信息,包括位置

来看一个文本块:

  1. size: 文本的大小。
  2. flags: 文本的标志。
  3. font: 字体名称。
  4. color: 字体颜色。
  5. ascender: 文本的上升高度。
  6. descender: 文本的下降高度。
  7. text: 文本内容。
  8. origin: 文本的起始位置坐标。
  9. bbox: 文本的边界框坐标,即左下角和右上角的坐标。

通过这些信息,我们可以获取到每个文本块的具体内容、大小、位置和格式等信息。这些信息对于分析和处理 PDF 文件中的文本内容非常有用。例如,你可以根据文本的大小、位置和格式来识别标题、正文和其他内容,并进行相应的处理和分析。当然,就以这个文档为例,我们可以看到的是,因为文档本身字体大小都一样,所以很难根据字体和大小获取到标题。

四、错误问题

 但是也发现了问题

4.1 段落有被分开了

原文

错误的问题如下

4.2 将表格错当成了文本内容

原文表格内容如下

 

解析得到的内容如下

表格的一行为一个块内容,

这里调试了一版,可以去掉表格。

逻辑是:判断相邻的block,表格的特征是,当个block内的 lines的 bbox的第四位是相同的。且相邻的block的lines一定是相同的,且lines不为空。逻辑本身没有问题,就怕PDF有问题,识别出来的表格的同一行的bbox中的第四位不一样,这样会错误判断!

import fitz  # PyMuPDF

def is_table_block(b1, b2):
    # 检查连续相邻的文本块是否具有相同的行数,并且其 bbox 的高度也相同
    if len(b1["lines"]) == len(b2["lines"]) and b1["bbox"][3] - b1["bbox"][1] == b2["bbox"][3] - b2["bbox"][1]:
        return True
    return False

def extract_text_blocks(pdf_path):
    # 打开 PDF 文件
    pdf_document = fitz.open(pdf_path)
    
    # 存储文本块信息
    text_blocks = []
    line_blocks = []
    
    # 遍历 PDF 中的每一页
    for page_number in range(len(pdf_document)):
        page = pdf_document.load_page(page_number)
        
        # 获取文本块和行块信息
        blocks = page.get_text("dict")["blocks"]
        for i in range(len(blocks)):
            if i < len(blocks) - 1 and is_table_block(blocks[i], blocks[i+1]):  # 如果是表格,则跳过
                continue
            for l in blocks[i]["lines"]:
                line_blocks.append({
                    "line": l["spans"],
                    "bbox": l["bbox"],
                    "height": l["bbox"][3] - l["bbox"][1]  # 计算行块的高度
                })
            text_blocks.append({
                "block": blocks[i]["lines"],
                "bbox": blocks[i]["bbox"]
            })
    
    # 关闭 PDF 文件
    pdf_document.close()
    
    return text_blocks, line_blocks

# 示例用法
pdf_path = "D:\\angus\\py\\困难pdf节选西藏奇正2022.pdf"
text_blocks, line_blocks = extract_text_blocks(pdf_path)

# 打印提取的文本块信息
# 用于检查两个文本块中的行是否相同
def check_lines_same(block1, block2):
    num_lines_block1 = len(block1["block"])
    num_lines_block2 = len(block2["block"])
    return num_lines_block1 == num_lines_block2

for index, block in enumerate(text_blocks):
    # 获取当前文本块中行的个数
    num_lines = len(block["block"])
    
    # 如果当前文本块是表格,则继续检查下一个文本块是否是表格
    if num_lines > 1 and index < len(text_blocks) - 1:  # 需要多于一行,并且不是最后一个文本块
        next_block = text_blocks[index + 1]
        if check_lines_same(block, next_block):
            # 如果下一个文本块也是表格,则跳过,不进行打印输出
            continue
    
    # 如果当前文本块不是表格,则打印输出
    print(f"Text Block {index + 1}:")
    for line_index, line in enumerate(block["block"]):
        print(f"  Line {line_index + 1}: '{line['spans']}' at position {block['bbox']}")


# 打印提取的行块信息
# for index, line in enumerate(line_blocks):
#     print(f"Line {index + 1}: '{line['line']}' at position {line['bbox']}, height={line['height']}")

4.3 解析丢失整行数据

测试了另外一个法律法规文件。

发现文件丢失了。原文件内容如下:

解析后的:

还没找到bug的原因。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1479591.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FreeRTOS 其它知识点

目录 一、低功耗Tickless模式 1、低功耗Tickless模式的引入 2、Tickless 具体实现 二、空闲任务 1、空闲任务相关知识点 2、钩子函数 3、空闲任务钩子函数 三、使用RTOS的好处 一、低功耗Tickless模式 1、低功耗Tickless模式的引入 FreeRTOS 的系统时钟是由滴答定时器中…

多个 JDK 版本(Java 8、Java 17、Java 21)下载和切换

文章目录 多个 JDK 版本&#xff08;Java 8、Java 17、Java 21&#xff09;下载和切换1. 下载 JDK2. 配置环境变量3. JDK 版本切换4. 测试5. 在 IDEA 中切换 JDK注意&#xff1a; 多个 JDK 版本&#xff08;Java 8、Java 17、Java 21&#xff09;下载和切换 随着 Spring Boot …

SAP 科目XXXX 不允许未资产负债表科目(AC305,AC306)

SAP 科目XXXX 不允许未资产负债表科目&#xff08;AC305&#xff0c;AC306&#xff09; AO90配置如下&#xff1a; 报错消息如下&#xff1a; 问题原因&#xff1a; 按照中国会计制度要求&#xff0c;对于固定资产的转出处置需要通过“固定资产清理”科目来过渡处理&#…

基于JAVA,SpringBoot和Vue二手商城交易系统设计

摘要 本课题旨在开发一个基于Java语言&#xff0c;结合SpringBoot框架和Vue前端技术的二手商城交易系统。这个系统提供一个用户友好的界面&#xff0c;使得用户可以方便地浏览、发布、购买和出售二手商品。通过使用SpringBoot作为后端服务框架&#xff0c;该系统能够快速搭建并…

基于SSM医院电子病历管理系统的设计与实现(源代码+数据库脚本+万字文档+PPT)

系统介绍 医院电子病历管理系统主要是借助计算机&#xff0c;通过对医院电子病历管理系统所需的信息管理&#xff0c;增加用户的选择&#xff0c;同时也方便对广大用户信息的及时查询、修改以及对用户信息的及时了解。医院电子病历管理系统 对用户带来了更多的便利&#xff0c…

nginx设置缓存时间、日志分割、开启多进程、网页压缩、配置防盗链

一、设置缓存时间 当网页数据返回给客户端后&#xff0c;可针对静态网页设置缓存时间&#xff0c;在配置文件内的http段内server段添加location&#xff0c;更改字段expires 1d来实现&#xff1a;避免重复请求&#xff0c;加快访问速度 第一步&#xff1a;修改主配置文件 #修…

Sora如何申请,Sora如何使用(最新详细教程)

引言 OpenAI发布的Sora模型以及有一段时间了~现在在tiktok的sora官网上也时长发布最新的视频。 OpenAI Tiktok的官网 那么普通人如何申请sora和使用sora呢&#xff0c;可以参考以下方式~ 1、虚假的Sora使用渠道2、真实的Sora使用渠道3、什么是OpenAI Red Teaming Network4、…

深度学习 精选笔记(2)自动求导与概率

学习参考&#xff1a; 动手学深度学习2.0Deep-Learning-with-TensorFlow-bookpytorchlightning ①如有冒犯、请联系侵删。 ②已写完的笔记文章会不定时一直修订修改(删、改、增)&#xff0c;以达到集多方教程的精华于一文的目的。 ③非常推荐上面&#xff08;学习参考&#x…

《HelloGitHub》第 95 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对编程感兴趣&#xff01; 简介 HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 Python、Java、Go、C/C、Swift...让你在短时间内…

第十一届教育与心理科学国际会议(ICEPS 2024)即将召开!

​ 2024年第十一届教育与心理科学国际会议&#xff08;ICEPS 2024&#xff09;将于2024年5月10-12日在泰国普吉岛万豪酒店举行。本次会议由泰国艺术大学主办&#xff0c;并得到日本实践女子大学的支持。ICEPS 2024旨在为来自世界各地教育相关领域的学者和专业人士提供一个齐聚一…

EMO在哪体验?阿里对口型视频生成工具EMO下载地址?阿里巴巴新模型EMO的技术原理

这几天,阿里的对口型视频生成工具EMO火了。根据官方宣传,EMO只需要上传一张图片和一段音频就可以一键生成对口型视频,而且视频中的嘴型还可以与声音匹配。这项技术支持多语言、对话、唱歌以及快速语速的适配,但也可能成为制造虚假视频的利器,因此一些名人可能需要警惕了。…

Springboot解决模块化架构搭建打包错误找不到父工程

Springboot解决模块化架构搭建打包错误找不到父工程 一、情况一找不到父工程依赖1、解决办法 二、情况二子工程相互依赖提示"程序包xxx不存在" 一、情况一找不到父工程依赖 报错信息 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:…

uniapp+vue基于Android的图书馆借阅系统qb4y3-nodejs-php-pyton

uni-app框架&#xff1a;使用Vue.js开发跨平台应用的前端框架&#xff0c;编写一套代码&#xff0c;可编译到Android、小程序等平台。 框架支持:springboot/django/php/Ssm/flask/express均支持 前端开发:vue 语言&#xff1a;pythonjavanode.jsphp均支持 运行软件:idea/eclip…

射影变换的一种解法

1、欧式变换 参考《计算机视觉中的多视图几何》1.4节定义。 欧式变换也叫等距变换&#xff0c;是刚体运动模型&#xff0c;可以表示为&#xff1a; 其中的ε1&#xff0c;更简洁的形式是&#xff1a; 2、相似变换 相似变换是一个等距变换和一个均匀缩放的复合&#xff0c;表…

【学习心得】浏览器开发者工具中出现的VM开头的JS文件是什么?

一、现象描述 在Chrome的开发者工具中&#xff0c;你可能会看到一些以“VM”开头的JavaScript文件&#xff08;如“VM111.js”&#xff09;。 二、VM文件到底是什么&#xff1f; “VM”表示的是Virtual Machine&#xff08;虚拟机&#xff09;&#xff0c;这些文件通常表示由浏…

数据结构之树结构(上)

存储方式 数组存储方式的分析 优点&#xff1a;通过下标方式访问元素&#xff0c;速度快。对于有序数组&#xff0c;还可使用二分查找提高检索速度。 缺点&#xff1a;如果要检索具体某个值&#xff0c;或者插入值&#xff08;按一定顺序&#xff09;会整体移动&#xff0c;效…

实时抓取SKU商品属性详细信息API数据接口(淘宝,某音)

item_sku-获取sku详细信息 taobao.item_sku详细信息 API公共参数 请求地址: https://api-gw.onebound.cn/taobao/item_sku 名称类型必须描述keyString是调用key&#xff08;演示示例&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地…

千帆杯——对话第一期最强挑战者

千帆杯——对话第一期最强挑战者 ​ 在2月22日晚&#xff0c;百度开展直播&#xff0c;邀请了千帆杯第一期最强挑战者杨之正、百度主任研发架构师董大祥老师、以及Datawhale成员司玉鑫为大家带来直播分享。我听了直播后&#xff0c;感觉受益匪浅&#xff0c;于是选择记录一下直…

基于springboot+vue的新冠病毒密接者跟踪系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

【Android】属性动画

在属性动画出现之前&#xff0c;Android 系统提供的动画只有帧动画和 View 动画。View 动画我们都了解&#xff0c;它提供了 AlphaAnimation、RotateAnimation、TranslateAnimation、ScaleAnimation 这4种动画方式&#xff0c;并提供了 AnimationSet 动画集合来混合使用多种动画…