【大宝徐】使用pyPDF2及PyMuPdf库更改pdf文件中文字及删除部分区域
评论
收藏

【大宝徐】使用pyPDF2及PyMuPdf库更改pdf文件中文字及删除部分区域

经验分享
大宝徐
2025-08-28 10:38·浏览量:723
大宝徐
影刀专家
影刀认证工程师
发布于 2025-08-28 10:36更新于 2025-08-28 10:38723浏览

要求将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}")

以上。


收藏3
全部评论1
最新
发布评论
评论