Python PDF Document Separator
The one script that shall yet again preclude the need for Adobe Acrobat Pro for splitting a large document into smaller ones.
Python PDF Document Separator
The one script that shall yet again preclude the need for Adobe Acrobat Pro for splitting a large document into smaller ones.

Created with DALL-E
Have you ever received a large PDF document that you wanted to split into smaller ones and annotate by date and name? You can write a simple script in Python to automate that process for multiple files in a folder.
Here is an example of a full dump of employee timesheets that need to be separated by name and annotated by date to create an archive of timesheets over a period of time for long-term storage:

A page from a typical employee timesheet document with employee name and timesheet period end date.
The components of the time sheet that matter are:
- Employee First Name
- Employee Last Name
- Timesheet Period End Date
The goal is to break up this 154-page document in this example into individual timesheets for each distinct employee that are typically 1 page but may extend to multiple depending on the complexity of their work week.
The file names of these individual timesheets shall be as follows:
{YYYY}-{MM}-{DD}_{LAST NAME}_{FIRST NAME}
Structure this process to have the Python program process files within a folder consisting of input files into another folder consisting of output files. Therefore, use the os and glob packages for both navigating between directories and grouping multiple files together:
# Packages for working with file structures
import os
import glob
Fortunately, since the PDF file is searchable and has a consistent structure, there is no need for any RegEx coding to find distinct patterns for search for as reference points. Rather, the PyPDF2 package and its classes PdfReader and PdfWriter can be deployed:
# Packages for processing PDF files
from PyPDF2 import PdfReader, PdfWriter
First, write a function for extracting the distinct first and last names from the top of the page, using the comma as a separator:
def extract_name(name_section):
"""
Extracts the last name and first name from a name section.
Handles cases with suffixes, multiple commas, or compound names.
"""
parts = name_section.split(",")
if len(parts) >= 2:
last_name = parts[0].strip()
first_name = "_".join([name.strip() for name in parts[1:]]).strip() # Join remaining parts for first name
else:
last_name, first_name = "UNKNOWN", "UNKNOWN"
return last_name, first_name
This code is designed to handle edge cases in which first names can be two words (e.g. “Lee Ann”, “James David”, etc.) or last names can be hyphenated (e.g. maiden name — marriage name) or suffixed (e.g. “Jr.”, “III”, etc.) by extracting the text before the first comma as the last name while extracting all other text separated by commas (“,”) as the first name and joined by underscores (“_”), to later by joined by them to the last name.
Next, write a function that shall call the function for extracting the names to process the page(s) containing the distinct employee timesheet.
Start by creating a directory to ensure that a folder to output the file exists, otherwise defaulting to using it:
# Ensure output directory exists
os.makedirs(output_directory, exist_ok=True)
Load the the PDF file that the timesheet is in by using the PdfReader class of PyPDF2:
# Load the PDF
reader = PdfReader(input_pdf_path)
This shall create an object containing the distinct pages of the file.
Initialize a dictionary for the distinct timesheets to be stored as individual pages in the values while the names extracted by the extract_name() function that you have just written shall form the keys:
# Initialize variables to group pages by individuals
grouped_timesheets = {}
current_name = None
Now cycle through each of the pages parsed by the PdfReader class of PyPDF2 extracting the names and elements of the date (year, month, and date) separated by slashes while reordering them in the the “YYYY-MM-DD” format required by the aforementioned filename convention:
# Parse each page in the PDF
for page in reader.pages:
text = page.extract_text()
if "Timesheet ending:" in text:
# Identify a new individual if a new heading is found
try:
extract_dates = text.split("Timesheet ending:")[1].split("|")[0].strip().split("/")
ending_date = "-".join([extract_dates[2], extract_dates[0], extract_dates[1]])
name_section = text.split("<TEXT BEFORE NAME>")[1].split("Timesheet ending:")[0].strip()
last_name, first_name = extract_name(name_section)
current_name = f"{ending_date}_{last_name}_{first_name}"
if current_name not in grouped_timesheets:
grouped_timesheets[current_name] = []
except Exception as e:
print(f"Error identifying individual on page: {e}")
current_name = None
# Add the page to the current individual's timesheet group
if current_name:
grouped_timesheets[current_name].append(page)
The text between the phrase “Timesheet ending:” and the first pipe (“|”) symbol shall be extracted using consecutive split() methods, stripped of additional white spaces using the strip() method, and then stored as a list of its respective elements applying the split() method to the forward slash (“/”) elements separating them. That list shall then be rearranged through the join() method using hyphens (“-”) in the desired format.
The text after a common identifier before the employee name (redacted) an before the phrase “Timesheet ending” shall be extracted and then supplied as input for the extract_name() function to obtain the distinct last_name and first_name variables.
Finally, the ending_date, last_name, and first_name shall be concatenated into the string variable currentname with **underscores (“”) to form a new key the grouped_timesheets dictionary with its respective page object from the reader.pages list of objects within the PdfReader()** class that the pages of the PDF document were loaded into.
The second half of this function shall be using the PdfWriter class of PyPDF2 to cycle through the distinct keys and values (the PDF pages themselves) in the grouped_timesheets dictionary to generate files named after their keys and containing their respective pages for each distinct employee:
# Write each individual's grouped timesheet to a single PDF
output_files = []
for name, pages in grouped_timesheets.items():
output_path = os.path.join(output_directory, f"{name}.pdf")
writer = PdfWriter()
for page in pages:
writer.add_page(page)
with open(output_path, "wb") as output_file:
writer.write(output_file)
output_files.append(output_path)
An optional step is to output which filenames were generated:
print(f"Generated files: {output_files}")
Therefore, the final function should look like this:
def process_timesheet_pdf(input_pdf_path, output_directory):
"""
Processes a timesheet PDF to split it into individual files.
Args:
input_pdf_path (str): Path to the input PDF file.
output_directory (str): Directory to save the individual timesheet files.
"""
# Ensure output directory exists
os.makedirs(output_directory, exist_ok=True)
# Load the PDF
reader = PdfReader(input_pdf_path)
# Initialize variables to group pages by individuals
grouped_timesheets = {}
current_name = None
# Parse each page in the PDF
for page in reader.pages:
text = page.extract_text()
if "Timesheet ending:" in text:
# Identify a new individual if a new heading is found
try:
extract_dates = text.split("Timesheet ending:")[1].split("|")[0].strip().split("/")
ending_date = "-".join([extract_dates[2], extract_dates[0], extract_dates[1]])
name_section = text.split("<TEXT BEFORE NAME>")[1].split("Timesheet ending:")[0].strip()
last_name, first_name = extract_name(name_section)
current_name = f"{ending_date}_{last_name}_{first_name}"
if current_name not in grouped_timesheets:
grouped_timesheets[current_name] = []
except Exception as e:
print(f"Error identifying individual on page: {e}")
current_name = None
# Add the page to the current individual's timesheet group
if current_name:
grouped_timesheets[current_name].append(page)
# Write each individual's grouped timesheet to a single PDF
output_files = []
for name, pages in grouped_timesheets.items():
output_path = os.path.join(output_directory, f"{name}.pdf")
writer = PdfWriter()
for page in pages:
writer.add_page(page)
with open(output_path, "wb") as output_file:
writer.write(output_file)
output_files.append(output_path)
# Optional
print(f"Generated files: {output_files}")
The third function that needs to be written shall now call this process_timesheet_pdf() function to iterate through multiple files placed in a directory of raw PDF files to be processed and deposited into the output directory:
# Data processing function to be performed on files within target folder
def process_file():
# Navigate to input file directory
path = os.getcwd()
source = '/'
input_folder = 'timesheets_input'
os.chdir(path + source + input_folder)
# Navigate to output file directory
output_folder = 'timesheets_output'
output_dir = path + source + output_folder
# Define the path to the directory containing the PDF files
all_files = glob.glob('*.pdf')
# Iterate through every file in the glob and check encoding
for file in all_files:
# Process PDF file
process_timesheet_pdf(file, output_dir)
The user can define the folder containing the files to be processed in the in the input_folder variable as well as the folder of processed files in the output_folder variable, with the path = os.getcwd() definition to ensure that the program is being directed to the directory where the program is stored. Ideally, keep the program in its own directory while separating the distinct folders for the input and output in their own subdirectories.
The glob method of the glob package is used to aggregate all the raw PDF files into one list called all_files that the process_timesheet_pdf() function shall cycle through.
Optionally, keep a counter within the process_file() function for keeping track of the progress, since this operation can be time-consuming:
...
# Define the path to the directory containing the PDF files
all_files = glob.glob('*.pdf')
file_count = len(all_files)
# Iterate through every file in the glob and check encoding
for index, file in enumerate(all_files):
# Process PDF file
print(f'Processing file {index} of {file_count}')
process_timesheet_pdf(file, output_dir)
print(f'Processed file {index} of {file_count}')
Finally, to make this an executable file (i.e. being able to be deployed in the terminal through python <filename>, be sure to specify this last function to be run by default at the very end:
if __name__ == "__main__":
process_file()
That is all to batch process a large volume of aggregated PDF files, such as timesheets, into individually named ones without having to purchase a copy of Adobe Acrobat Pro. Here is the final completed code:
# Packages for working with file structures
import os
import glob
# Packages for processing PDF files
from PyPDF2 import PdfReader, PdfWriter
def extract_name(name_section):
"""
Extracts the last name and first name from a name section.
Handles cases with suffixes, multiple commas, or compound names.
"""
parts = name_section.split(",")
if len(parts) >= 2:
last_name = parts[0].strip()
first_name = "_".join([name.strip() for name in parts[1:]]).strip() # Join remaining parts for first name
else:
last_name, first_name = "UNKNOWN", "UNKNOWN"
return last_name, first_name
def process_timesheet_pdf(input_pdf_path, output_directory):
"""
Processes a timesheet PDF to split it into individual files.
Args:
input_pdf_path (str): Path to the input PDF file.
output_directory (str): Directory to save the individual timesheet files.
"""
# Ensure output directory exists
os.makedirs(output_directory, exist_ok=True)
# Load the PDF
reader = PdfReader(input_pdf_path)
# Initialize variables to group pages by individuals
grouped_timesheets = {}
current_name = None
# Parse each page in the PDF
for page in reader.pages:
text = page.extract_text()
if "Timesheet ending:" in text:
# Identify a new individual if a new heading is found
try:
extract_dates = text.split("Timesheet ending:")[1].split("|")[0].strip().split("/")
ending_date = "-".join([extract_dates[2], extract_dates[0], extract_dates[1]])
name_section = text.split("<TEXT BEFORE NAME>")[1].split("Timesheet ending:")[0].strip()
last_name, first_name = extract_name(name_section)
current_name = f"{ending_date}_{last_name}_{first_name}"
if current_name not in grouped_timesheets:
grouped_timesheets[current_name] = []
except Exception as e:
print(f"Error identifying individual on page: {e}")
current_name = None
# Add the page to the current individual's timesheet group
if current_name:
grouped_timesheets[current_name].append(page)
# Write each individual's grouped timesheet to a single PDF
output_files = []
for name, pages in grouped_timesheets.items():
output_path = os.path.join(output_directory, f"{name}.pdf")
writer = PdfWriter()
for page in pages:
writer.add_page(page)
with open(output_path, "wb") as output_file:
writer.write(output_file)
output_files.append(output_path)
# Optional
print(f"Generated files: {output_files}")
# Data processing function to be performed on files within target folder
def process_file():
# Navigate to input file directory
path = os.getcwd()
source = '/'
input_folder = 'timesheets_input'
os.chdir(path + source + input_folder)
# Navigate to output file directory
output_folder = 'timesheets_output'
output_dir = path + source + output_folder
# Define the path to the directory containing the PDF files
all_files = glob.glob('*.pdf')
file_count = len(all_files)
# Iterate through every file in the glob and check encoding
for index, file in enumerate(all_files):
# Process PDF file
print(f'Processing file {index} of {file_count}')
process_timesheet_pdf(file, output_dir)
print(f'Processed file {index} of {file_count}')
if __name__ == "__main__":
process_file()
The PyPDF2 package of Python is extremely powerful for bulk document processing and should be an essential tool for all business intelligence developers and information technology specialists to boost the productivity of their respective enterprise organizations.
메타데이터
- post_id
- 9a6e1c482b60
- slug
- pdf-document-separator-9a6e1c482b60
- url
- https://blog.gopenai.com/pdf-document-separator-9a6e1c482b60
- canonical_url
- https://blog.gopenai.com/pdf-document-separator-9a6e1c482b60
- author_url
- https://medium.com/@chatterjee.prime
- status
- ok
- fetched_at
- 2026-07-21 06:32:45