zbparse/flask_app/main/截取pdf.py

201 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from PyPDF2 import PdfReader, PdfWriter
import re # 导入正则表达式库
import os # 用于文件和文件夹操作
def clean_page_numbers(text):
# 使用正则表达式删除页码
# 假设页码在文本的最开始,紧跟着文字且无空格分隔
cleaned_text = re.sub(r'^\s*\d+\s*(?=\D)', '', text) # 删除开头的页码,仅当紧跟非数字字符时
# 删除结尾的页码
cleaned_text = re.sub(r'\s+\d+\s*$', '', cleaned_text)
# 删除形如 /129 的页码
cleaned_text = re.sub(r'\s*\/\s*\d+\\s*', '', cleaned_text)
return cleaned_text
def save_pages_to_new_pdf(pdf_path, output_folder, output_suffix, start_page, end_page):
"""从原始PDF截取指定范围的页面并保存到新的PDF文件中"""
# 获取文件基本名称
base_file_name = os.path.splitext(os.path.basename(pdf_path))[0]
# 构建输出文件路径
output_pdf_path = os.path.join(output_folder, f"{base_file_name}_{output_suffix}.pdf")
# 读取PDF文件
pdf_document = PdfReader(pdf_path)
output_doc = PdfWriter()
# 检查起始和结束页码是否有效
if start_page is not None and end_page is not None and start_page <= end_page:
# 添加指定范围的页面到新的PDF文档中
for page_num in range(start_page, end_page + 1):
output_doc.add_page(pdf_document.pages[page_num])
# 保存新的PDF文件
with open(output_pdf_path, 'wb') as f:
output_doc.write(f)
print(f"已截取并保存页面从 {start_page + 1}{end_page + 1}{output_pdf_path}")
else:
print("提供的页码范围无效。")
return output_pdf_path
def extract_pages_twice(pdf_path, output_folder, output_suffix): #第一次截取失败
if output_suffix == "qualification":
common_pattern = r'^(?:附录(?:一)?[:]|附件(?:一)?[:]|附表(?:一)?[:])'
end_pattern = r'^(第[一二三四五六七八九十]+章\s*投标人须知|评标办法|评标办法前附表)'
pdf_document = PdfReader(pdf_path)
start_page = None
end_page = None
for i, page in enumerate(pdf_document.pages):
text = page.extract_text()
if text:
cleaned_text = clean_page_numbers(text)
# 如果还未找到起始页,检查当前页是否满足条件作为起始页
if start_page is None and "资格审查" in cleaned_text:
if re.search(common_pattern, cleaned_text, re.MULTILINE):
start_page = i # 存储符合条件的页码页码从1开始
# 检查当前页是否满足条件作为结束页
if start_page is not None and re.search(end_pattern, cleaned_text, re.MULTILINE):
if i > start_page:
end_page = i # 存储符合条件的结束页码页码从1开始
break # 可选:找到结束页后退出循环
if start_page is None or end_page is None:
print(f"未找到起始或结束页在文件 {pdf_path} 中!")
return ""
else:
return save_pages_to_new_pdf(pdf_path,output_folder,output_suffix,start_page,end_page)
elif output_suffix == "invalid":
pdf_document = PdfReader(pdf_path)
total_pages = len(pdf_document.pages)
# 计算总页数的三分之二
total = int(total_pages * 2 / 3)
start_page=1
end_page = min(90, total)
return save_pages_to_new_pdf(pdf_path, output_folder, output_suffix, start_page, end_page)
def extract_pages(pdf_path, output_folder, begin_pattern, begin_page, end_pattern, output_suffix):
# 打开PDF文件
pdf_document = PdfReader(pdf_path)
start_page = None
end_page = None
# 遍历文档的每一页,查找开始和结束短语的位置
for i in range(len(pdf_document.pages)):
page = pdf_document.pages[i]
text = page.extract_text()
if text:
cleaned_text = clean_page_numbers(text)
# print(cleaned_text)
if re.search(begin_pattern, cleaned_text) and i > begin_page:
if output_suffix == "invalid" and start_page: #仅当提取Invalid的时候判断初始页码是第一个匹配到的页码因为招标编号可能存在多个后面的覆盖前面
continue
else:
start_page = i
if start_page is not None and re.search(end_pattern, cleaned_text):
# 如果output_suffix是"qualification",调整条件检查
if output_suffix == "qualification":
condition = i > start_page
else:
condition = i > (start_page + 1)
if condition:
is_invalid_condition = output_suffix == "invalid" and i > 30 #这边默认无效投标至少有30页
if is_invalid_condition or output_suffix != "invalid":
end_page = i
break
# 确保找到了起始和结束页面
if start_page is None or end_page is None:
if output_suffix == "qualification" or "invalid":
extract_pages_twice(pdf_path, output_folder, output_suffix)
else:
print(f"未找到起始或结束页在文件 {pdf_path} 中!")
return ""
else:
return save_pages_to_new_pdf(pdf_path, output_folder, output_suffix, start_page, end_page)
def process_input(input_path, output_folder, begin_pattern, begin_page, end_pattern, output_suffix):
# 确保输出文件夹存在
if not os.path.exists(output_folder):
os.makedirs(output_folder)
if os.path.isdir(input_path):
generated_files = []
# 遍历文件夹内的所有PDF文件
for file in os.listdir(input_path):
if file.endswith(".pdf"):
pdf_path = os.path.join(input_path, file)
output_pdf_path = extract_pages(pdf_path, output_folder, begin_pattern, begin_page, end_pattern, output_suffix)
if output_pdf_path and os.path.isfile(output_pdf_path):
generated_files.append(output_pdf_path)
return generated_files
elif os.path.isfile(input_path) and input_path.endswith(".pdf"):
# 处理单个PDF文件
output_pdf_path = extract_pages(input_path, output_folder, begin_pattern, begin_page, end_pattern, output_suffix)
if output_pdf_path and os.path.isfile(output_pdf_path):
return [output_pdf_path] # 以列表形式返回,以保持一致性
else:
print("提供的路径既不是文件夹也不是PDF文件。")
return []
def truncate_pdf_main(input_path, output_folder, selection):
if selection == 1:
# Configure patterns and phrases for "投标人须知前附表"
begin_pattern = re.compile(r'第[一二三四五六七八九十]+章\s*投标人须知')
begin_page = 3
end_pattern = re.compile(r'投标人须知正文')
output_suffix = "tobidders_notice_table"
elif selection == 2:
# Configure patterns and phrases for "评标办法"
begin_pattern = re.compile(r'第[一二三四五六七八九十]+章\s*评标办法') #考虑到这种情况 '第三章 第三章 第三章 第三章 评标办法 评标办法 评标办法 评标办法'
begin_page = 10
end_pattern = re.compile(r'评标办法正文|评标办法')
output_suffix = "evaluation_method"
elif selection == 3:
# Configure patterns and phrases for "投标人须知正文"
begin_pattern = re.compile(r'投标人须知正文')
begin_page = 5
end_pattern = re.compile(r'^第[一二三四五六七八九十]+章\s*评标办法|^评标办法前附表|^附录(?:一)?[:]|^附件(?:一)?[:]|^附表(?:一)?[:]', re.MULTILINE)
output_suffix = "tobidders_notice"
elif selection==4:
# 配置用于 "资格审查条件" 的正则表达式模式和短语
common_pattern = r'^(?:附录(?:一)?[:]|附件(?:一)?[:]|附表(?:一)?[:])'
begin_pattern = re.compile(common_pattern + r'.*(?:资质|能力|信誉).*$', re.MULTILINE)
begin_page = 5
end_pattern = re.compile(
common_pattern + r'(?!.*(?:资质|能力|信誉)).*$|' # 原有的模式
r'^(第[一二三四五六七八九十]+章\s*评标办法|评标办法前附表)', # 新增的匹配项
re.MULTILINE
)
output_suffix = "qualification"
elif selection == 5:
# 配置用于 "无效标" 的正则表达式模式和短语
begin_pattern = re.compile(r'第[一二三四五六七八九十]+章\s*招标公告|第一卷|招标编号:|招标编号:')
begin_page = 0
end_pattern = re.compile(r'第[一二三四五六七八九十]+章\s*合同|[:]清标报告|第二卷', re.MULTILINE)
output_suffix = "invalid"
else:
print("无效的选择")
return None
# Process the selected input
return process_input(input_path, output_folder, begin_pattern, begin_page, end_pattern, output_suffix)
def truncate_pdf_multiple(input_path, output_folder):
truncate_files = []
for selection in range(1, 5):
files = truncate_pdf_main(input_path, output_folder, selection)
truncate_files.extend(files)
return truncate_files
#TODO:需要完善二次请求。目前invalid一定能返回 前附表 须知正文如果为空的话要额外处理一下比如说就不进行跳转见xx表 开评定标这里也要考虑 如果评分表为空,也要处理。
if __name__ == "__main__":
input_path = "C:\\Users\\Administrator\\Desktop\\招标文件\\招标test文件夹"
output_folder = "C:\\Users\\Administrator\\Desktop\\招标文件\\招标test文件夹"
# truncate_pdf_multiple(input_path,output_folder)
selection = 5 # 例如1 - 投标人须知前附表, 2 - 评标办法, 3 - 投标人须知正文 4-资格审查条件 5-无效标
generated_files = truncate_pdf_main(input_path, output_folder, selection)
# # print("生成的文件:", generated_files)