

要求将Pdf文件中某页单独提取出来,根据页面中Factory Code调整下方表格中日期,将该日期减少20天或10天后更新,以及删除Notes后文字。

好在这些批量问题每页格式都完全相同,比较好处理。期间翻了下PyMuPdf的中文文档 1.26.0 版本
处理方式:
先使用PyPDF2库将原pdf文档中某页提取出来, 然后创建一个临时文件。提取临时文件中Facetory Code确定要减少的天数,提取表格中的日期确定更新后的日期,使用PyMuPdf库实现提取日期文字的位置,在指定位置偏移将改文字位置先用page.draw_rect白色框覆盖原日期文本, 然后在该白色框位置使用page.insert_text填写更新后的日期文字,文字大小及字体确保和原来一致。删除Notes后内容也是通过Notes的位置确定后续文字内容区域,然后以page.draw_rect以白色框覆盖。最后将临时文件保存为最终文件。

代码(部分)
import os
import re
import PyPDF2
import pdfplumber
#import pandas as pd
from datetime import datetime, timedelta
from dateutil import parser
import tempfile
import shutil
import fitz #pymupdf
def _create_single_page_pdf(input_pdf, page_num, output_path):
"""创建单页PDF文件"""
pdf_writer = PyPDF2.PdfWriter()
pdf_reader = PyPDF2.PdfReader(input_pdf)
pdf_writer.add_page(pdf_reader.pages[page_num])
try:
with open(output_path, 'wb') as output_file:
pdf_writer.write(output_file)
except OSError as e:
print(f"创建PDF文件时出错: {str(e)}")
# 尝试使用更简单的文件名
dir_name = os.path.dirname(output_path)
base_name = os.path.basename(output_path)
simple_name = f"page_{page_num+1}.pdf"
new_path = os.path.join(dir_name, simple_name)
with open(new_path, 'wb') as output_file:
pdf_writer.write(output_file)
print(f"已使用简化文件名保存: {simple_name}")
return new_path
return output_path
def _process_file2(input_pdf, page_num, output_path, text):
"""处理文件2,根据Factory Code调整第二列日期并删除Notes内容"""
# 创建临时单页PDF
temp_dir = os.path.dirname(output_path)
temp_filename = f"temp_page_{page_num+1}_{datetime.now().strftime('%H%M%S')}.pdf"
temp_pdf_path = os.path.join(temp_dir, temp_filename)
try:
_create_single_page_pdf(input_pdf, page_num, temp_pdf_path)
except Exception as e:
print(f"创建临时PDF文件时出错: {str(e)}")
# 如果创建临时文件失败,直接复制原始页面
_create_single_page_pdf(input_pdf, page_num, output_path)
return
# 检查Factory Code - 尝试更多模式
factory_code_patterns = [
r'Factory\s*Code[::]\s*(\w+)',
r'Factory\s+Code\s*(\w+)',
r'FACTORY\s*CODE[::]\s*(\w+)',
r'Factory[::]\s*(\w+)',
r'工厂代码[::]\s*(\w+)',
r'F\s*a\s*c\s*t\s*o\s*r\s*y\s*C\s*o\s*d\s*e\s*[::]\s*(\w+)',
r'F\s*a\s*c\s*t\s*o\s*r\s*y\s*C\s*o\s*d\s*e\s*(\w+)'
]
factory_code = None
for pattern in factory_code_patterns:
match = re.search(pattern, text, re.IGNORECASE)
if match:
factory_code = match.group(1).strip()
print(f"找到工厂代码: {factory_code}")
break
# 如果没有找到Factory Code,尝试查找文本中包含"Factory Code"附近的代码
if not factory_code:
factory_code_pos = text.lower().find("factory code")
if factory_code_pos != -1:
# 在"Factory Code"后面的文本中查找代码
after_factory_code = text[factory_code_pos:factory_code_pos + 30] # 查找后面30个字符
code_match = re.search(r'[::]\s*(\w+)', after_factory_code)
if code_match:
factory_code = code_match.group(1)
print(f"在'Factory Code'附近找到代码: {factory_code}")
if not factory_code:
# 尝试查找NPW或NPV或NPC的直接出现
if "NPW" in text:
factory_code = "NPW"
print("在文本中直接找到NPW")
elif "NPV" in text:
factory_code = "NPV"
print("在文本中直接找到NPV")
elif "NPC" in text:
factory_code = "NPC" # 按照NPV处理
print("在文本中直接找到NPC")
else:
print("警告:无法在文档中找到Factory Code,将不进行日期调整")
factory_code = "Unknown"
# 根据Factory Code确定需要减少的天数
days_to_reduce = 0
if factory_code == "NPW":
days_to_reduce = 20
print(f"检测到Factory Code为NPW,将减少20天")
elif factory_code == "NPV" or factory_code == "NPC":
days_to_reduce = 10
print(f"检测到Factory Code为{factory_code},将减少10天")
# 使用pymupdf处理PDF内容
try:
# 使用pymupdf打开PDF
doc = fitz.open(temp_pdf_path)
page = doc[0] #当前临时文件只有一页
# 1. 查找并修改表格中的日期
# 获取页面上的所有文本块及其位置
text_instances = page.get_text("dict")["blocks"]
# 查找包含日期的文本块
for block in text_instances:
if "lines" in block:
for line in block["lines"]:
for span in line["spans"]:
text_content = span["text"]
# 查找日期格式的文本
date_matches = re.findall(r'(\d{2}/\d{2}/\d{2,4})', text_content)
if date_matches:
print(f"date_matches: {date_matches}")
for date_str in date_matches:
try:
# 判断日期格式是否是 mm/dd/yy
if len(date_str) > 8:
continue
# 判断这个日期是否在表格的第二列
# 简单假设:如果x坐标在页面的特定范围内,则认为是表格第二列
bbox = span["bbox"]
print(f"bbox: {bbox}")
x_pos = bbox[0] # 文本的x坐标
page_width = page.rect.width
page_height = page.rect.height
print(f"page width:{page_width},height:{page_height}")
fontsize=span["size"]
fontname = span["font"]
print(f"span size: {fontsize}, font name: {fontname}")
# 假设表格第二列在页面宽度的1%-20%之间
if x_pos > page_width * 0.01 and x_pos < page_width * 0.20:
date_obj = parser.parse(date_str, dayfirst=False)
new_date = date_obj - timedelta(days=days_to_reduce)
# 保持原始格式
if len(date_str.split('/')[2]) == 2:
new_date_str = new_date.strftime("%m/%d/%y")
else:
new_date_str = new_date.strftime("%m/%d/%Y")
print(f"{date_str}-->{new_date_str}")
# 用白色矩形覆盖原文本
rect = fitz.Rect(bbox[0]+16, bbox[1]+2, bbox[0]+60, bbox[1]+15) #范围求证
page.draw_rect(rect, color=(1, 1, 1), fill=(1, 1, 1), overlay=True)#白色矩形白色边框
#page.draw_rect(rect, color=(0, 0, 0), fill=(1, 1, 1), overlay=True)#白色矩形黑色边框,测试
# 写入新日期
page.insert_text(
(bbox[0]+18, bbox[1] + (bbox[3] - bbox[1]) * 0.8),
new_date_str,
fontsize=span["size"],
fontname=span["font"],
color=(0, 0, 0)
)
print(f"已修改日期: {date_str} -> {new_date_str}")
except Exception as e:
print(f"处理日期 '{date_str}' 时出错: {str(e)}")
# 2. 删除Notes内容
# 查找Notes文本
notes_instances = page.search_for("Notes:")
if notes_instances:
# 获取Notes文本的位置
notes_rect = notes_instances[0]
print(f"notes_rect: {notes_rect}")
# 查找Notes后面的所有文本
# 创建一个矩形覆盖从Notes开始到页面底部的区域
full_page_rect = page.rect
cover_rect = fitz.Rect(
notes_rect.x1+8, notes_rect.y0-6.8,
full_page_rect.width*0.95, full_page_rect.height*0.95
)
# 用白色矩形覆盖Notes及其后面的内容
page.draw_rect(cover_rect, color=(1, 1, 1), fill=(1, 1, 1), overlay=True)#白色矩形白色边框
#page.draw_rect(cover_rect, color=(0, 0, 0), fill=(1, 1, 1), overlay=True)#白色矩形黑色边框,测试
print("已删除Notes及其后面的内容")
# 保存修改后的PDF
doc.save(output_path)
doc.close()
print(f"文件2处理完成: Factory Code = {factory_code}, 日期调整 = {days_to_reduce}天")
except Exception as e:
print(f"处理PDF内容时出错: {str(e)}")
# 如果处理失败,直接复制原始页面
_create_single_page_pdf(input_pdf, page_num, output_path)
# 删除临时文件
if os.path.exists(temp_pdf_path):
try:
os.remove(temp_pdf_path)
except:
print(f"无法删除临时文件: {temp_pdf_path}")以上。