当前位置: 首页 > news >正文

pdf 文件版面分析--pdfplumber (python 文档解析提取)

pdfplumber 的特点

1、它是一个纯 python 第三方库,适合 python 3.x 版本
2、它用来查看pdf各类信息,能有效提取文本、表格
3、它不支持修改或生成pdf,也不支持对pdf扫描件的处理

import glob
import pdfplumber
import re
from collections import defaultdict
import jsonclass PDFProcessor:def __init__(self, filepath):self.filepath = filepath#打开文档,注意存放的位置self.pdf = pdfplumber.open(filepath)self.all_text = defaultdict(dict)self.allrow = 0self.last_num = 0def check_lines(self, page, top, buttom):# 文本数据lines = page.extract_words()[::]text = ''last_top = 0last_check = 0for l in range(len(lines)):each_line = lines[l]check_re = '(?:。|;|单位:元|单位:万元|币种:人民币|\d|报告(?:全文)?(?:(修订版)|(修订稿)|(更正后))?)$'if top == '' and buttom == '':if abs(last_top - each_line['top']) <= 2:text = text + each_line['text']#elif last_check > 0 and (page.height * 0.85 - each_line['top']) > 0 and not re.search(check_re, text):elif last_check > 0 and (page.height * 0.9 - each_line['top']) > 0 and not re.search(check_re, text):text = text + each_line['text']else:text = text + '\n' + each_line['text']elif top == '':if each_line['top'] > buttom:if abs(last_top - each_line['top']) <= 2:text = text + each_line['text']elif last_check > 0 and (page.height * 0.85 - each_line['top']) > 0 and not re.search(check_re,text):text = text + each_line['text']else:text = text + '\n' + each_line['text']else:if each_line['top'] < top and each_line['top'] > buttom:if abs(last_top - each_line['top']) <= 2:text = text + each_line['text']elif last_check > 0 and (page.height * 0.85 - each_line['top']) > 0 and not re.search(check_re,text):text = text + each_line['text']else:text = text + '\n' + each_line['text']last_top = each_line['top']last_check = each_line['x1'] - page.width * 0.85return textdef drop_empty_cols(self, data):# 删除所有列为空数据的列transposed_data = list(map(list, zip(*data)))filtered_data = [col for col in transposed_data if not all(cell is '' for cell in col)]result = list(map(list, zip(*filtered_data)))return result@staticmethoddef keep_visible_lines(obj):"""If the object is a ``rect`` type, keep it only if the lines are visible.A visible line is the one having ``non_stroking_color`` not null."""if obj['object_type'] == 'rect':if obj['non_stroking_color'] is None:return Falseif obj['width'] < 1 and obj['height'] < 1:return False# return obj['width'] >= 1 and obj['height'] >= 1 and obj['non_stroking_color'] is not Noneif obj['object_type'] == 'char':return obj['stroking_color'] is not None and obj['non_stroking_color'] is not Nonereturn Truedef extract_text_and_tables(self, page):buttom = 0page = page.filter(self.keep_visible_lines)tables = page.find_tables()if len(tables) >= 1:# 表格数据count = len(tables)for table in tables:if table.bbox[3] < buttom:passelse:count -= 1top = table.bbox[1]text = self.check_lines(page, top, buttom)text_list = text.split('\n')for _t in range(len(text_list)):self.all_text[self.allrow] = {'page': page.page_number, 'allrow': self.allrow,'type': 'text', 'inside': text_list[_t]}self.allrow += 1buttom = table.bbox[3]new_table = table.extract()r_count = 0for r in range(len(new_table)):row = new_table[r]if row[0] is None:r_count += 1for c in range(len(row)):if row[c] is not None and row[c] not in ['', ' ']:if new_table[r - r_count][c] is None:new_table[r - r_count][c] = row[c]else:new_table[r - r_count][c] += row[c]new_table[r][c] = Noneelse:r_count = 0end_table = []for row in new_table:if row[0] != None:cell_list = []cell_check = Falsefor cell in row:if cell != None:cell = cell.replace('\n', '')else:cell = ''if cell != '':cell_check = Truecell_list.append(cell)if cell_check == True:end_table.append(cell_list)end_table = self.drop_empty_cols(end_table)for row in end_table:self.all_text[self.allrow] = {'page': page.page_number, 'allrow': self.allrow,'type': 'excel', 'inside': str(row)}# self.all_text[self.allrow] = {'page': page.page_number, 'allrow': self.allrow, 'type': 'excel',#                               'inside': ' '.join(row)}self.allrow += 1if count == 0:text = self.check_lines(page, '', buttom)text_list = text.split('\n')for _t in range(len(text_list)):self.all_text[self.allrow] = {'page': page.page_number, 'allrow': self.allrow,'type': 'text', 'inside': text_list[_t]}self.allrow += 1else:#文本数据text = self.check_lines(page, '', '')text_list = text.split('\n')for _t in range(len(text_list)):self.all_text[self.allrow] = {'page': page.page_number, 'allrow': self.allrow,'type': 'text', 'inside': text_list[_t]}self.allrow += 1first_re = '[^计](?:报告(?:全文)?(?:(修订版)|(修订稿)|(更正后))?)$'end_re = '^(?:\d|\\|\/|第|共|页|-|_| ){1,}'if self.last_num == 0:try:first_text = str(self.all_text[1]['inside'])end_text = str(self.all_text[len(self.all_text) - 1]['inside'])if re.search(first_re, first_text) and not '[' in end_text:self.all_text[1]['type'] = '页眉'if re.search(end_re, end_text) and not '[' in end_text:self.all_text[len(self.all_text) - 1]['type'] = '页脚'except:print(page.page_number)else:try:first_text = str(self.all_text[self.last_num + 2]['inside'])end_text = str(self.all_text[len(self.all_text) - 1]['inside'])if re.search(first_re, first_text) and '[' not in end_text:self.all_text[self.last_num + 2]['type'] = '页眉'if re.search(end_re, end_text) and '[' not in end_text:self.all_text[len(self.all_text) - 1]['type'] = '页脚'except:print(page.page_number)self.last_num = len(self.all_text) - 1def process_pdf(self):for i in range(len(self.pdf.pages)):self.extract_text_and_tables(self.pdf.pages[i])def save_all_text(self, path):with open(path, 'w', encoding='utf-8') as file:for key in self.all_text.keys():file.write(json.dumps(self.all_text[key], ensure_ascii=False) + '\n')def process_all_pdfs_in_folder(folder_path):file_paths = glob.glob(f'{folder_path}/*')file_paths = sorted(file_paths, reverse=True)for file_path in file_paths:print(file_path)try:processor = PDFProcessor(file_path)processor.process_pdf()save_path = 'RAG_ASMPLE_DATAS_TXTS/' + file_path.split('/')[-1].replace('.pdf', '.txt')processor.save_all_text(save_path)except:print('check')if __name__ == '__main__':# 需要解析的pdf文件路径pdf_path = r'C:\Users\WWS\RAG_ASMPLE_DATAS\2020-02-26__上海爱旭新能源股份有限公司__600732__爱旭股份__2019年__年度报告.pdf'# pdf解析后的txt内容文件out_path = r'C:\Users\WWS\RAG_ASMPLE_DATAS\2020-02-26__上海爱旭新能源股份有限公司__600732__爱旭股份__2019年__年度报告.txt'processor = PDFProcessor(pdf_path)processor.process_pdf()processor.save_all_text(out_path)

参考

版面分析–PDF解析神器pdfplumber
版面分析–富文本txt读取

补充


提取PDF中的图片并保存到本地

import pdfplumber
file_name = "**.pdf"# 需要解析的pdf的文件路径
output_file = "**.xlsx" # pdf解析后的内容with pdfplumber.open(file_name) as pdf:#获取第一页first_page = pdf.pages[1]print('页码:', first_page.page_number)print('page width:', first_page.width)print('page height:', first_page.height)# get the first page texttext = first_page.extract_text()print(text)# 获取第一页图片,获取到的是一个列表,列表中存储的是字典imgs = first_page.imagesi = 0for img in imgs:# 获取图片的二进制流print(img['stream'].get_data())with open(output_file, mode='wb') as f2:f2.write(img['stream'].get_data())

提取pdf 表格文本,保存为excel文件

import pdfplumber
from openpyxl import Workbook# 保存表格,需要安装openpyxl
file_name = '**.pdf'
output_file = '**.xlsx'
with pdfplumber.open(file_name) as pdf:page01 = pdf.pages[0]table = page01.extract_table()workbook = Workbook()sheet = workbook.activefor row in table:sheet.append(row)workbook.save(filename=output_file)

提取PDF表格 文本

import pdfplumber
file_name = '**.pdf'
output_file = '**.txt'
with pdfplumber.open(file_name) as p:page_count = len(p.pages)# 统计文档的页数for i in range(0, page_count):page = p.pages[i]# 提取每页的对象并存储textdata = page.extract_table()#提取每页的表格文字信息# table2 = page01.extract_tables()# 提取多个表格data = open(output_file , 'a') # 将 表格文字存放在需要存储的文档里面data.write(textdata )# 文档内容写入

提取PDF纯文本

import pdfplumber
file_name = '**.pdf'
output_file = '**.txt'
with pdfplumber.open(file_name) as p:page_count = len(p.pages)# 统计文档的页数for i in range(0, page_count):page = p.pages[i]# 提取每页的对象并存储textdata = page.extract_text()#提取每页的文字信息data = open(output_file , 'a') # 将 表格文字存放在需要存储的文档里面data.write(textdata )# 文档内容写入

读取富文本txt
python 读取文件函数有三种 read()、readline()、readlines()

  • read() 一次性读取所有文本
  • readline() 读取第一行的内容
  • readlines() 读取全部内容,以数列的格式返回
with open('rag_datas/story.txt', 'r', encoding='utf-8' ) as f:data = f.read()print(data)
with open('rag_datas/story.txt', 'r', encoding='utf-8' ) as f:data = f.readline()print(data)
with open('rag_datas/story.txt', 'r', encoding='utf-8' ) as f:for line in f.readlines():line = line.strip('\n')print(line)

相关文章:

pdf 文件版面分析--pdfplumber (python 文档解析提取)

pdfplumber 的特点 1、它是一个纯 python 第三方库&#xff0c;适合 python 3.x 版本 2、它用来查看pdf各类信息&#xff0c;能有效提取文本、表格 3、它不支持修改或生成pdf&#xff0c;也不支持对pdf扫描件的处理 import glob import pdfplumber import re from collection…...

PostgreSQL的学习心得和知识总结(一百四十三)|深入理解PostgreSQL数据库之Support event trigger for logoff

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《PostgreSQL数据库内核分析》 2、参考书籍&#xff1a;《数据库事务处理的艺术&#xff1a;事务管理与并发控制》 3、PostgreSQL数据库仓库…...

https免费证书获取

获取免费证书的网址&#xff1a; Certbot 1. 进入你的linux系统&#xff0c;先安装snapd&#xff0c; yum install snapd 2. 启动snapd service snapd start 3.安装 Certbot snap install --classic certbot 注意如下出现此错误时&#xff0c;需要先建立snap 软连接后&am…...

C语言 | Leetcode C语言题解之第74题搜索二维矩阵

题目&#xff1a; 题解&#xff1a; bool searchMatrix(int** matrix, int matrixSize, int* matrixColSize, int target) {int m matrixSize, n matrixColSize[0];int low 0, high m * n - 1;while (low < high) {int mid (high - low) / 2 low;int x matrix[mid /…...

杰发科技AC7840——软件Sent_HAL39X

0. 序 使用PWM模拟Sent测试下7840的软件sent功能。 参考链接&#xff1a;SENT协议应用笔记 - TechPlus汽车工坊的文章 - 知乎 SENT协议 1. Sent功能测试 使用提供的软件Sent代码在7840上测试&#xff0c;接收数据OK 2. 参考资料 3. 数据解析 我们个根据上述参考资料尝试解析…...

IOS 开发 - block 使用详解

1.Blobk的定义 block的写法相对难记,不必司机应被,只需要在xcode里打出"inlineBlock"--回车, 系统会自动帮你把基础版写法给你匹配出来 //Block的基础声明//等号""之前是blobk的声明,等号“”后面是block的实现/*returnType:返回类型(void、int、String *…...

BUU-[极客大挑战 2019]Http

考察点 信息收集 http构造请求数据包 题目 解题步骤 参考文章&#xff1a;https://zhuanlan.zhihu.com/p/367051798 查看源代码 发现有一个a标签&#xff0c;但是οnclick"return false"就是点击后不会去跳转到Secret.php的页面 所以我就自己拼接url http://no…...

开发Web3 ETF的技术难点

开发Web3 ETF&#xff08;Exchange-Traded Fund&#xff0c;交易所交易基金&#xff09;软件时&#xff0c;需要注意以下几个关键问题。开发Web3 ETF软件是一个复杂的过程&#xff0c;涉及到金融、法律和技术多个领域的专业知识。开发团队需要综合考虑上述问题&#xff0c;以确…...

【K8s】Kubectl 常用命令梳理

Kubectl常用命令梳理 下面包含大致涵盖命令只需要替换对应的Pod \ NameSpace 查看 命名空间 是 ’worktest2‘ 下 名字包括 ’todo‘的所有 Pod kubectl -n worktest2 get pod|grep todo查看 所有命名空间下 名字包括 ’todo‘的所有 Pod kubectl get pods --all-namespace…...

机器学习-监督学习

监督学习是机器学习和人工智能中的一个重要分支&#xff0c;它涉及使用已标记的数据集来训练算法&#xff0c;以便对数据进行分类或准确预测结果。监督学习的核心在于通过输入数据&#xff08;特征&#xff09;和输出数据&#xff08;标签或类别&#xff09;之间的关系&#xf…...

搭建Docker私服镜像仓库Harbor

1、概述 Harbor是由VMware公司开源的企业级的Docker Registry管理项目&#xff0c;它包括权限管理(RBAC)、LDAP、日志审核、管理界面、自我注册、镜像复制和中文支持等功能。 Harbor 的所有组件都在 Dcoker 中部署&#xff0c;所以 Harbor 可使用 Docker Compose 快速部署。 …...

SpringBoot自定义初始化sql文件 支持多类型数据库

我在resources目录下有init.sql初始化sql语句 指定sql文件的地址 sql内容如下&#xff1a; /*角色表*/ INSERT INTO #{schema}ccc_base_role (id, create_time, create_user_id, is_delete, role_name, status, update_time, update_user_id) VALUES(b89e30d81acb88448d412…...

nginx--FastCGI

CGI 概念 nginx通过与第三方基于协议实现&#xff0c;即通过某种特定协议将客户端请求转发给第三方服务处理&#xff0c;第三方服务器会新建新的进程处理用户的请求&#xff0c;处理完成后返回数据给Nginx并回收进程(下次处理有需要新建)&#xff0c;最后nginx在返回给客户端…...

【数据结构】浅谈

✨✨✨专栏&#xff1a;数据结构 &#x1f9d1;‍&#x1f393;个人主页&#xff1a;SWsunlight 目录 一、概念&#xff1a; 二、物理结构&#xff1a; 1、顺序存储结构&#xff1a; 2、链式存储结构&#xff1a; 3、数据索引存储结构: 4、数据散列存储结构&#xf…...

简洁大气APP下载单页源码

源码介绍 简洁大气APP下载单页源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面 效果截图 源码下载 简洁大气APP下载单页源码...

ICode国际青少年编程竞赛- Python-4级训练场-复杂嵌套for循环

ICode国际青少年编程竞赛- Python-4级训练场-复杂嵌套for循环 1、 for i in range(4):Dev.step(i6)for j in range(3):Dev.turnLeft()Dev.step(2)2、 for i in range(4):Dev.step(i3)for j in range(4):Dev.step(2)Dev.turnRight()Dev.step(-i-3)Dev.turnRight()3、 for i …...

Idea入门:一分钟创建一个Java工程

一&#xff0c;新建一个Java工程 1&#xff0c;启动Idea后&#xff0c;选择 [New Project] 2&#xff0c;完善工程信息 填写工程名称&#xff0c;根据实际用途取有意义的英文名称选择Java语言&#xff0c;可以看到还支持Kotlin、Javascript等语言选择包管理和项目构建工具Mav…...

QGraphicsView实现简易地图8『缓存视口周边瓦片』

前文链接&#xff1a;QGraphicsView实现简易地图7『异步加载-多瓦片-无底图』 前7篇的地图加载&#xff0c;都采用最少瓦片数量的算法&#xff0c;即用最少数量的瓦片覆盖视口&#xff0c;以获得最快的加载速度。但是这样会带来一个问题&#xff0c;那就是每当移动地图时&#…...

如何在Java项目中使用Spring Boot快速连接达梦数据库(DM)

前言 在Java开发领域&#xff0c;Spring Boot凭借其简洁快速的特性成为现代应用开发的首选框架。本文将详细介绍如何在Spring Boot项目中整合JDBC以快速连接达梦数据库(DM)&#xff0c;并提供一个简单的示例来验证连接是否成功。 一、环境准备与依赖配置 在开始之前&#xf…...

QT中的容器

Qt中的容器 关于Qt中的容器类&#xff0c;下面我们来进行一个总结&#xff1a; Qt的容器类比标准模板库&#xff08;STL&#xff09;中的容器类更轻巧、安全和易于使用。这些容器类是隐式共享和可重入的&#xff0c;而且他们进行了速度和存储的优化&#xff0c;因此可以减少可…...

Taotoken的API Key管理与审计日志功能保障企业调用安全

Taotoken的API Key管理与审计日志功能保障企业调用安全 1. 企业级API Key管理 在Taotoken平台上&#xff0c;企业管理员可以创建多个API Key&#xff0c;并为每个Key分配不同的权限和使用限制。这一功能特别适合需要将大模型能力集成到多个项目或分配给不同团队的企业用户。 …...

终极指南:如何用WzComparerR2突破冒险岛游戏数据解析的三大技术壁垒

终极指南&#xff1a;如何用WzComparerR2突破冒险岛游戏数据解析的三大技术壁垒 【免费下载链接】WzComparerR2 Maplestory online Extractor 项目地址: https://gitcode.com/gh_mirrors/wz/WzComparerR2 在游戏逆向工程和数据提取领域&#xff0c;冒险岛的WZ文件格式一…...

7天突破编程障碍:游戏化学习的完整实战指南

7天突破编程障碍&#xff1a;游戏化学习的完整实战指南 【免费下载链接】codecombat Game for learning how to code. 项目地址: https://gitcode.com/gh_mirrors/co/codecombat 你还记得第一次面对编程时的感受吗&#xff1f;那些冰冷的语法规则、抽象的算法概念&#…...

3种方式彻底解决音乐文件加密问题:Unlock-Music完整实践指南

3种方式彻底解决音乐文件加密问题&#xff1a;Unlock-Music完整实践指南 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库&#xff1a; 1. https://github.com/unlock-music/unlock-music &#xff1b;2. https://git.unlock-music.dev/um/web 项目地址:…...

别再手动写表单了!用这个Vue3+TS+Element Plus的TQueryCondition组件,5分钟搞定后台管理筛选页

Vue3TSElement Plus高效封装&#xff1a;TQueryCondition组件深度实战指南 后台管理系统开发中&#xff0c;最枯燥的重复劳动莫过于编写各种筛选表单。每次新增一个列表页&#xff0c;就要重写一遍日期范围选择、下拉筛选、输入框联动这些基础功能。这种低效模式正在被新一代组…...

创维E900V22C电视盒子CoreELEC评测与实战指南:从闲置设备到4K媒体中心

创维E900V22C电视盒子CoreELEC评测与实战指南&#xff1a;从闲置设备到4K媒体中心 【免费下载链接】e900v22c-CoreELEC Build CoreELEC for Skyworth e900v22c 项目地址: https://gitcode.com/gh_mirrors/e9/e900v22c-CoreELEC 将闲置的创维E900V22C电视盒子改造为专业级…...

从电气柜到PC机箱:运动控制卡(如固高、雷赛)与PLC(西门子、三菱)的实战开发体验对比

从电气柜到PC机箱&#xff1a;运动控制卡与PLC的实战开发体验对比 第一次从PLC梯形图编程切换到C#调用运动控制卡API时&#xff0c;那种感觉就像突然从手动挡换成了自动驾驶——虽然最终目的地相同&#xff0c;但操作方式和驾驶体验截然不同。作为在工业自动化领域摸爬滚打多年…...

别再只用第三方库了!拆解React悬浮按钮的3种实现方案与选型指南

别再只用第三方库了&#xff01;拆解React悬浮按钮的3种实现方案与选型指南 悬浮交互组件在现代Web应用中越来越常见&#xff0c;从客服系统的快捷入口到游戏辅助工具的操作面板&#xff0c;这类元素既能提升用户体验&#xff0c;又不会占用宝贵的页面空间。但面对项目需求时&a…...

2026年晋城文化墙设计大揭秘,独特创意究竟藏着什么奥秘?

在晋城&#xff0c;文化墙不仅是城市的一道风景线&#xff0c;更是文化传承与创新的重要载体。2026年&#xff0c;晋城飞达广告有限公司设计的文化墙展现出了独特的魅力&#xff0c;让我们一起揭开其背后的奥秘。一、深度融合文化理念数据支撑据不完全统计&#xff0c;晋城飞达…...

YOLO11性能暴增:Backbone换血 | 彻底替换为EfficientViT,微软CVPR2023神作,实现高分辨率图像的实时检测

一、开篇:目标检测的速度困局与Transformer浪潮 计算机视觉领域在过去十年里经历了一场深刻的范式转变。从手工设计特征到CNN的全面接管,再到如今Vision Transformer(ViT)的强势崛起,每一次变革都带来了性能的巨大飞跃。YOLO系列作为实时目标检测的标杆框架,已经走到了第…...