需求背景:
-
问题描述 :
我有一份包含多份合同的PDF文件,需要将这些合同分开并进行解析。
传统方法(如以固定页数作为分割点)不够灵活,无法满足需求。
-
现有方法的不足 :
网上找到的工具大多依赖手动输入页数作为分割点,这种方式不够智能,且需要用户提前知道每份合同的页数范围,效率较低。
灵感核心:
-
动态分割点 :
通过输入一个唯一关键字(如"合同编号"、"甲方"等)来自动定位合同的分割点,从而实现自动分割。
-
实现步骤:
1、将PDF文件的每一页转换为图片。
2、使用OCR技术识别图片内容,提取关键字。
3、定位关键字所在的页码,并将这些页码作为分割点。
4、使用PDF处理工具将PDF文件拆分为多个独立文件。
注意:1,2步是因为我的PDF文件包含图片,读取内容困难,所以采用OCR识别技术提取文字。如果你的不是就可以修改成直接读取pdf文件内容。
代码实现
1、用到了百度OCR所以需要去获取access_token,代码如下:
python
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 token
else:
print("错误信息:", response.content)
return response
2、具体实现代码
需要提前下载以下库:PyMuPDF,requests,PyPDF2
python
import re
from PyPDF2 import PdfReader, PdfWriter
import fitz # PyMuPDF
import base64
import os
import requests
def 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
# 分割PDF
for 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()