首页  >  文章  >  后端开发  >  轻松拆分和重命名 Skyward 的 PDF

轻松拆分和重命名 Skyward 的 PDF

王林
王林原创
2024-07-30 01:14:33771浏览

Easily Split and Rename PDFs for Skyward

为什么要建造它以及它有什么作用

几周前,我的主管给了我一个挑战,看看我是否可以针对我们遇到的特定问题提出一个工作流程。我们希望将 Pre/ACT 信件放入我们的 SMS(学生管理系统)中,在我们的例子中是 Skyward。我们遇到的问题是,Pre/ACT 信件要么是批量 PDF,要么是单独的 PDF,要进入 Skyward,我们需要每个学生的姓名作为 ID 号的 PDF。为了实现这一目标,我决定用 Python 编写一个程序,并使用 Streamlit 作为 UI。

让我们看看我们需要解决的问题,从 PDF 开始。获取信件的批量单个 PDF 导出更有意义,这意味着我们需要将批量导出拆分为单独的 PDF。虽然每个字母通常有 2 页,但情况并非总是如此,因此每隔一页进行简单的分隔可能很容易出错。

第二个问题是读取每个学生的PDF并将其重命名为相应的ID Number。这主要取决于能够满足我需要的正则表达式模式。

由于这也是一个时间挑战,我与 AI 合作来帮助生成代码。注意:这并不能替代了解您正在使用的逻辑和语言。当使用 AI/LLM 编写本文时,我使用了思维链方法,给出了我想要的小块,然后在添加更多块之前调试和测试每个块。下面的代码是最终使用的代码,我将逐节分解每个代码。如果您希望在您的学区将此作为解决方案实施,请参阅本文末尾的 TLDR。

要求和进口

这部分相当简单,是程序运行的基础。

  • 我们的 UI 的 Streamlit
  • 用于 PDF 操作的 pypdf2、pymupdf 和 fitz

requirements.txt内容

streamlit
pypdf2
fitz
pymupdf

app.py 导入

import PyPDF2
import fitz  # PyMuPDF
import re
from pathlib import Path
import concurrent.futures
import streamlit as st
import shutil
import zipfile
import os

寻找ID

下一个片段涉及在批量 PDF 中查找 ID 并创建用于拆分它们的页面列表,这是取决于正则表达式的部分,可能需要根据您的情况进行更改。

def find_id_pages(input_pdf):
 doc = fitz.open(input_pdf)
 id_pages = []
 id_pattern = re.compile(r'\(ID#:\s*(\d+)\)')

    for i, page in enumerate(doc):
 text = page.get_text()
        if id_pattern.search(text):
 id_pages.append(i)

    return id_pages

分割 PDF

正如标题所说,这是用来分割PDF的。这将使用一个函数来提取每个 PDF 的名称。您还会注意到,这会将它们并行拆分(一次最多 10 个),以提高性能。

def split_pdf(input_pdf, output_folder, progress_callback):
 input_path = Path(input_pdf)
 output_folder = Path(output_folder)
 output_folder.mkdir(parents=True, exist_ok=True)

    # Find pages with IDs
 id_pages = find_id_pages(input_pdf)

    if not id_pages:
 st.error("No ID pages found in the PDF.")
        return

 pdf_reader = PyPDF2.PdfReader(str(input_path))
 total_pages = len(pdf_reader.pages)
 temp_pdfs = []

    for i in range(len(id_pages)):
 start_page = id_pages[i]
 end_page = id_pages[i + 1] if i + 1 < len(id_pages) else total_pages

 pdf_writer = PyPDF2.PdfWriter()
        for j in range(start_page, end_page):
 pdf_writer.add_page(pdf_reader.pages[j])

 temp_pdf_path = output_folder / f'temp_{i}.pdf'
        with open(temp_pdf_path, 'wb') as output_pdf:
 pdf_writer.write(output_pdf)

 temp_pdfs.append(temp_pdf_path)
 progress_callback((i + 1) / len(id_pages))  # Update progress bar

    # Process renaming in parallel
    with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
 executor.map(lambda pdf_path: extract_and_rename_pdf(pdf_path, output_folder), temp_pdfs)
def extract_and_rename_pdf(pdf_path, output_folder):
 doc = fitz.open(pdf_path)
 text_first_page = doc[0].get_text()

    # Extract ID using a regex pattern for the format (ID#: 01234)
 match_first_page = re.search(r'\(ID#:\s*(\d+)\)', text_first_page)

    if match_first_page:
 id_value = match_first_page.group(1)
 new_pdf_path = output_folder / f'{id_value}.pdf'
 pdf_path.rename(new_pdf_path)
    else:
 new_pdf_path = output_folder / f'unknown_{pdf_path.stem}.pdf'
 pdf_path.rename(new_pdf_path)

快到了

接下来是几个简短的函数,一个用于压缩所有拆分的 PDF(如果您想在内部服务器上运行它),另一个用于清理任何临时文件,这样就不会出现 PII 学生信息它不需要生存。

def zip_output_folder(output_folder, zip_name):
 shutil.make_archive(zip_name, 'zip', output_folder)
def clean_up(output_folder, zip_name):
 shutil.rmtree(output_folder)
 os.remove(f"{zip_name}.zip")

构建用户界面

最后一段代码是用于 UI 的。 Streamlit 是一个多功能的 WebUI(是的,您可以单独运行它)。经过几次尝试并考虑可用性。为了简单起见,我将其简化为上传按钮、操作按钮(即拆分)和下载按钮以获取压缩的 PDF。

# Streamlit App Portion
st.title("PDF Splitter and Renamer")

uploaded_file = st.file_uploader("Choose a PDF file", type="pdf")
output_folder = "output_folder"

if st.button("Split and Rename PDF"):
    if uploaded_file and output_folder:
        try:
            # Save uploaded file temporarily
            with open("temp_input.pdf", "wb") as f:
 f.write(uploaded_file.getbuffer())

 progress_bar = st.progress(0)
            def update_progress(progress):
 progress_bar.progress(progress)

 split_pdf("temp_input.pdf", output_folder, update_progress)

 zip_name = "output_pdfs"
 zip_output_folder(output_folder, zip_name)
 st.success("PDF split and renamed successfully!")

            with open(f"{zip_name}.zip", "rb") as f:
 st.download_button(
                    label="Download ZIP",
                    data=f,
                    file_name=f"{zip_name}.zip",
                    mime="application/zip"
 )

            # Remove temporary file
 Path("temp_input.pdf").unlink()
 clean_up(output_folder, zip_name)
        except Exception as e:
 st.error(f"An error occurred: {e}")
    else:
 st.error("Please upload a PDF file and specify an output folder.")

TLDR 启动并运行

要启动并运行,只需使用以下命令(假设为 Linux、WSL 和 MacOS)。您可以通过访问 http://localhost:8501 来访问该应用程序。

git clone https://github.com/Blacknight318/act-to-sms.git
cd act-to-sms
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
streamlit run app.py

结束语

如果您就读于 K12 学校,我希望这对您有所帮助。如果是这样,请鼓掌或考虑给我买杯咖啡。下次再见,顺风顺水。

以上是轻松拆分和重命名 Skyward 的 PDF的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn