基于关键字定位的自动化PDF合同拆分
需求背景:
-
问题描述:
我有一份包含多份合同的PDF文件,需要将这些合同分开并进行解析。
传统方法(如以固定页数作为分割点)不够灵活,无法满足需求。 -
现有方法的不足:
网上找到的工具大多依赖手动输入页数作为分割点,这种方式不够智能,且需要用户提前知道每份合同的页数范围,效率较低。
灵感核心:
-
动态分割点:
通过输入一个唯一关键字(如“合同编号”、“甲方”等)来自动定位合同的分割点,从而实现自动分割。 -
实现步骤:
1、将PDF文件的每一页转换为图片。
2、使用OCR技术识别图片内容,提取关键字。
3、定位关键字所在的页码,并将这些页码作为分割点。
4、使用PDF处理工具将PDF文件拆分为多个独立文件。
注意:1,2步是因为我的PDF文件包含图片,读取内容困难,所以采用OCR识别技术提取文字。如果你的不是就可以修改成直接读取pdf文件内容。
代码实现
1、用到了百度OCR所以需要去获取access_token,代码如下:
import requests
import json"""
client_id,client_secret去百度OCR中获取
详情看链接:https://ai.baidu.com/ai-doc/REFERENCE/Ck3dwjhhu
"""def getAccessToken(client_id, client_secret):url = f"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={client_id}&client_secret={client_secret}"payload = ""headers = {'Content-Type': 'application/json','Accept': 'application/json'}response = requests.request("POST", url, headers=headers, data=payload)if str(response) == "<Response [200]>":# print(response.text)# 将JSON字符串解析为字典data = json.loads(response.text)token = data.get("access_token")print("执行成功:", response)print("access_token:", token)return tokenelse:print("错误信息:", response.content)return response
2、具体实现代码
需要提前下载以下库:PyMuPDF,requests,PyPDF2
import re
from PyPDF2 import PdfReader, PdfWriter
import fitz # PyMuPDF
import base64
import os
import requestsdef pdf_to_images(pdf_path, output_folder, dpi=300):"""将PDF文件的每一页转换为图片。参数:pdf_path (str): 输入PDF文件的路径。output_folder (str): 输出图片文件夹路径。dpi (int): 图片分辨率,默认为300 DPI。"""# 确保输出文件夹存在if not os.path.exists(output_folder):os.makedirs(output_folder)# 打开PDF文件doc = fitz.open(pdf_path)# 遍历每一页并转换为图片for page_num in range(len(doc)):page = doc.load_page(page_num)pix = page.get_pixmap(dpi=dpi)image_path = os.path.join(output_folder, f"page_{page_num + 1}.png")pix.save(image_path)print(f"已保存图片:{image_path}")def perform_ocr(image_path, access_token):"""对单个图片文件进行OCR识别。参数:image_path (str): 图片文件的路径。access_token (str): OCR API的访问令牌。返回:str: OCR识别结果。"""ocr_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic"headers = {'Content-Type': 'application/x-www-form-urlencoded'}# 读取图片文件并进行Base64编码with open(image_path, 'rb') as img_file:img_data = base64.b64encode(img_file.read())# 发送OCR请求response = requests.post(f"{ocr_url}?access_token={access_token}",data={'image': img_data},headers=headers)# 解析OCR结果if response.status_code == 200:ocr_result = response.json()return '。'.join(item['words'] for item in ocr_result.get('words_result', []))return ""def find_split_pages(image_folder, access_token, search_text):"""查找包含目标文本的页码。参数:image_folder (str): 包含图片的文件夹路径。access_token (str): OCR API的访问令牌。search_text (str): 要查找的文本。返回:list: 包含目标文本的页码列表。"""split_pages = []# 遍历图片文件夹中的所有图片for filename in os.listdir(image_folder):if filename.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp')):image_path = os.path.join(image_folder, filename)result = perform_ocr(image_path, access_token)# 提取页码并检查是否包含目标文本page_num = int(re.findall(r'\d+', filename)[0])if search_text in result:split_pages.append(page_num)return sorted(split_pages)def split_pdf(input_pdf, split_pages, output_folder):"""根据指定的页码分割PDF文件。参数:input_pdf (str): 输入PDF文件的路径。split_pages (list): 分割点页码列表。output_folder (str): 输出文件夹路径。"""# 确保输出文件夹存在if not os.path.exists(output_folder):os.makedirs(output_folder)# 获取输入PDF的文件名前缀output_prefix = os.path.splitext(os.path.basename(input_pdf))[0]# 打开PDF文件with open(input_pdf, 'rb') as pdf_file:reader = PdfReader(pdf_file)prev_split = 0# 分割PDFfor part_num, split_page in enumerate(split_pages, 1):writer = PdfWriter()for page_num in range(prev_split, split_page):writer.add_page(reader.pages[page_num])output_path = os.path.join(output_folder, f"{output_prefix}_part{part_num}.pdf")with open(output_path, 'wb') as output_file:writer.write(output_file)print(f"已保存分割文件:{output_path}")prev_split = split_page# 保存剩余部分if prev_split < len(reader.pages):writer = PdfWriter()for page_num in range(prev_split, len(reader.pages)):writer.add_page(reader.pages[page_num])output_path = os.path.join(output_folder, f"{output_prefix}_part{len(split_pages) + 1}.pdf")with open(output_path, 'wb') as output_file:writer.write(output_file)print(f"已保存最后分割文件:{output_path}")def main():# 输入和输出路径input_pdf = r"D:\project\合同\供应商版本采购合同\1月份合同.pdf"image_folder = r"D:\project\合同\供应商版本采购合同\分割"output_folder = r"D:\project\合同\供应商版本采购合同\分割结果"# OCR相关参数search_text = "双方买卖约定"access_token = "24.2******"# 将PDF转换为图片pdf_to_images(input_pdf, image_folder)# 查找包含目标文本的页码split_pages = find_split_pages(image_folder, access_token, search_text)if not split_pages:print(f"未找到包含文本 '{search_text}' 的页,无法进行分割。")return# 分割PDF文件split_pdf(input_pdf, split_pages, output_folder)if __name__ == "__main__":main()
相关文章:
基于关键字定位的自动化PDF合同拆分
需求背景: 问题描述: 我有一份包含多份合同的PDF文件,需要将这些合同分开并进行解析。 传统方法(如以固定页数作为分割点)不够灵活,无法满足需求。 现有方法的不足: 网上找到的工具大多依赖手动…...
spring security 使用auth2.0
在 Spring Security 中集成 OAuth 2.0 可以实现安全的第三方认证和资源保护。以下是完整的配置指南和代码示例: 一、OAuth 2.0 核心概念 角色作用资源所有者用户(授权访问资源的人)客户端应用(如Web、移动端)授权服务…...
NO.82十六届蓝桥杯备战|动态规划-从记忆化搜索到动态规划|下楼梯|数字三角形(C++)
记忆化搜索 在搜索的过程中,如果搜索树中有很多重复的结点,此时可以通过⼀个"备忘录",记录第⼀次搜索到的结果。当下⼀次搜索到这个结点时,直接在"备忘录"⾥⾯找结果。其中,搜索树中的⼀个⼀个结点…...
ubuntu 服务器版本常见问题
一、系统安装与初始化 1. 安装过程中断或失败 原因:镜像损坏、硬件兼容性、磁盘分区错误。 解决: 验证 ISO 文件的完整性(计算 SHA256 校验和)。 检查 BIOS/UEFI 设置(禁用 Secure Boot)。 使用手动分区模式,确保根分区(/)和 EFI 分区(如有)正确配置。 2. 系…...
【时时三省】(C语言基础)用switch语句实现多分支选择结构 例题
山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 例题: 用switch语句处理菜单命令。在许多应用程序中,用菜单对流程进行控制,例如从键盘输入一个 A 或 a 字符,就会执行A操作,输入一…...
全域数字化:从“智慧城市”到“数字生命体”的进化之路
一、国家战略下的城市数字化浪潮 2024年5月,国家四部委联合发布《关于深化智慧城市发展 推进城市全域数字化转型的指导意见》,明确提出以数据为引擎,系统性重塑城市技术架构与管理流程,推动城市治理迈向“全域协同、数实融合”的…...
Java网络编程干货
1.网络编程是什么 了解 在Java语言中,我们可以使用java.net包下的技术轻松开发出常见的网络应用程序,从而把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统&#x…...
如何在 Spring Boot 项目中使用 MyBatis 进行批量操作以提升性能?
MyBatis 提供了 ExecutorType.BATCH 类型,允许将多个 SQL 语句进行组合,最后统一执行,从而减少数据库的访问频率,提升性能。 以下是如何在 Spring Boot 项目中使用 MyBatis 进行批量操作的关键点: 1. 配置 MyBatis 使…...
基于SSM的线上花店鲜花销售商城网站系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…...
Python Lambda表达式详解
Python Lambda表达式详解 1. Lambda是什么? Lambda是Python中用于创建匿名函数(没有名字的函数)的关键字,核心特点是简洁。它适用于需要临时定义简单函数的场景,或直接作为参数传递给高阶函数(如map()、f…...
DAPP实战篇:使用web3.js连接合约
说明 本系列内容目录:专栏:区块链入门到放弃查看目录 如果你还没有创建好项目请先查看:《DApp实战篇:先用前端起个项目》,如果你还不知道web3.js是什么请先查看:《DApp实战篇:前端技术栈一览》。 安装 点此查看web3.js官方文档 打开项目根目录,并唤起终端: 键入w…...
linux sar 系统运行状态统计
概述 sar 命令来自英文词组**“System activity reporter”**的缩写,其功能是用于统计系统运行状态。是一个系统活动报告工具,用于收集、报告和保存系统活动信息。它可以帮助系统管理员监控和分析系统性能,识别潜在的性能瓶颈或问题。 实时…...
【C#】一种优雅的基于winform的串口通信管理
serialPort.DataReceived、串口优雅管理 完整《C#串口通信系统》功能清单 Part 1 — SerialPortManager.cs —— 串口核心管理类 using System; using System.IO.Ports; using System.Text; using System.Threading; using System.Windows.Forms;/// <summary> /// 专业…...
ChatGPT之智能驾驶问题讨论
ChatGPT之智能驾驶问题讨论 1. 源由2. 问题:2.1 智能驾驶级别定义🚗 L2(部分自动化,Partial Automation)🤖 L3(有条件自动化,Conditional Automation)🛸 L4&a…...
K8S-证书过期更新
K8S证书过期问题 K8S证书过期处理方法 Unable to connect to the server: x509: certificate has expired or is not yet valid 1、查看证书有效期: # kubeadm certs check-expiration2、备份证书 # cp -rp /etc/kubernetes /etc/kubernetes.bak3、直接重建证书 …...
蓝桥杯第十五届真题——握手问题
#include<bits/stdc.h> using namespace std; int main() {ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int sum0;for(int i7;i<49;i){sumi;}cout<<sum;return 0; }...
5G_WiFi_CE_DFS
目录 一、规范要求 1、法规目录 2、定义 3、运行模式 4、主/从设备相关的运行行为及具体的动态频率选择(DFS)要求 5、产品角色确定测试项目 6、测试项目 测试项1:信道可用性检查(Channel Availability Check) …...
第二节:React 基础篇-受控组件 vs 非受控组件
一、场景题:设计一个实时搜索输入框,说明选择依据 受控组件 vs 非受控组件 核心区别 特征受控组件非受控组件数据管理由React状态(state)控制通过DOM元素(ref)直接访问更新时机每次输入触发onChange提交…...
springboot 处理编码的格式为opus的音频数据解决方案【java8】
opus编码的格式概念: Opus是一个有损声音编码的格式,由Xiph.Org基金会开发,之后由IETF(互联网工程任务组)进行标准化,目标是希望用单一格式包含声音和语音,取代Speex和Vorbis,且适用…...
RK3568 基于Gstreamer的多媒体调试记录
文章目录 1、环境介绍2、概念理清3、提前准备4、GStreamer编译5、GStreamer基础介绍6、视频播放初体验7、视频硬编码7.1、h2647.2、h265 8、视频硬解码8.1、解码视频并播放8.2、解码视频并播放带音频 1、环境介绍 硬件:飞凌ok3568-c开发板 软件:原厂rk…...
VS Code 的 .S 汇编文件里面的注释不显示绿色
1. 确认文件语言模式 打开 .S 文件后,查看 VS Code 右下角的状态栏,确认当前文件的识别模式(如 Assembly、Plain Text 等)。如果显示为 Plain Text 或其他非汇编模式: 点击状态栏中的语言模式(如 Plain Te…...
在 Wireshark 中如何筛选数据包
1. 显示过滤器(Display Filters) 显示过滤器用于 在已捕获的数据包中筛选,语法类似于编程语言中的条件表达式。 (1)基本过滤 表达式说明ip.addr 192.168.1.1显示所有涉及 192.168.1.1 的 IP 包ip.src 192.168.1.1…...
[MySQL]数据库与表创建
欢迎来到啾啾的博客🐱。 这是一个致力于构建完善 Java 程序员知识体系的博客📚。 它记录学习点滴,分享工作思考和实用技巧,偶尔也分享一些杂谈💬。 欢迎评论交流,感谢您的阅读😄。 本篇简单记录…...
5分钟读懂ArgoCD:在Kubernetes中实现持续部署
Kubernetes中的Argo CD介绍 Argo CD是用于Kubernetes的声明式GitOps持续交付工具。它遵循GitOps模式,以Git仓库作为定义所需应用程序状态的唯一真实来源,能在指定的目标环境中自动部署应用程序,并持续监控应用程序的运行状态,确保…...
cs224w课程学习笔记-第10课
cs224w课程学习笔记-第10课 异构图 前言一、异构图1、异构图定义2、异构图与同构图 二、异构图下的GNN1、GCN扩展至RGCN1.1 RGCN原理1.2 异构图的任务预测特点1.3 异构图任务预测基础案例 2、完整的异构图GCN三、异构图下的Transformer 前言 异构图的定义是节点内部存在类型不…...
OpenCV 图形API(26)图像滤波-----方框滤波函数boxFilter()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 使用方框滤波器模糊图像。 该函数使用以下内核来平滑图像: K α [ 1 1 … 1 1 1 … 1 ⋮ ⋮ ⋱ ⋮ 1 1 … 1 ] K \alpha \begin{b…...
安卓手机怎样开启双WiFi加速
1. 小米/Redmi手机 路径: 设置 → WLAN → 高级设置 → 双WLAN加速 操作: 开启功能后,可同时连接一个2.4GHz WiFi和一个5GHz WiFi(或两个不同路由器)。 可选择“智能选择”或手动指定辅助网络。 2. 华为/荣耀手机…...
大模型上下文协议MCP详解(2)—核心功能
版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl1. 标准化上下文交互技术 1.1 实时数据接入能力 MCP(Model Context Protocol)通过标准化的接口,为 AI 模型提供了强大的实时数据接入能力,使其能够快速获取和处理来自不同数据源的实时信息。…...
剑指Offer(数据结构与算法面试题精讲)C++版——day8
剑指Offer(数据结构与算法面试题精讲)C版——day8 题目一:链表中环的入口节点题目二:两个链表的第1个重合节点题目三:反转链表附录:源码gitee仓库 题目一:链表中环的入口节点 这道题的有如下三个…...
【Qt】QxOrm:下载、安装、使用
1、下载源码 github地址:https://github.com/QxOrm/QxOrm 稳定版本下载:https://github.com/QxOrm/QxOrm/releases/tag/1.5.0 2、编译源码 QxOrm支持cmake编译(CMakeLists.txt)、Qt pro工程编译(QxOrm.pro) 以 QxOrm.pro 为例,编译生成的库,没有在 build-QxOrm-1.5…...
