pdf analyseren met python tutorial blog afbeelding

Hoe analyseer ik een PDF in Python? Stap voor stap tutorial

Het kan voorkomen dat je als bijvoorbeeld data analist moet werken met een dataset vanuit een PDF-bestand. Idealiter probeer je altijd de data alsnog in een gestructureerd formaat te verkrijgen, zoals in CSV- of JSON-formaat. Maar het kan zijn dat dit niet mogelijk is. Denk aan data die verkregen is via een export vanuit een programma of systeem. Waarbij er ofwel geen andere exportopties zijn, of hier niet voor gekozen is. Dit kan bijvoorbeeld een PDF zijn met hierin een grote tabel met financiële transacties. Om weer met de data in tabelvorm te kunnen werken, zul je enkele handelingen moeten verrichten.

In deze blog laten we vanuit een voorbeeld zien hoe je stap voor stap een PDF met hierin data in tabelvorm uitleest met programmeertaal Python. Om deze vervolgens verder te kunnen gebruiken.

1. Voorbeeld PDF: financiële transacties

In deze blog gaan we met een voorbeeld PDF-bestand met hierin een tabel met financiële transacties, verdeeld over 28 pagina's. De eerste pagina ziet er als volgt uit:

voorbeeld PDF inlezen en analyseren met Python 1

De tweede pagina:

voorbeeld PDF inlezen en analyseren met Python 2

En de laatste (28e) pagina:

voorbeeld PDF inlezen en analyseren met Python 28

We zien hierin dat de eerste pagina algemene gegevens bevat, en kolomnamen. Vervolgens een verzameling rijen met financiële transacties. De tweede pagina tot en met de laatste pagina bevatten geen algemene gegevens, maar alleen rijen met financiële transacties.

In deze blog gaan we de rijen met financiële transacties vanuit alle pagina's met Python uitlezen naar een pandas DataFrame. Om het vervolgens op te kunnen slaan in een gestructureerd formaat, zoals een CSV-bestand. Ook voeren we een simpele analyse uit met de data.

2. Uitlezen van een PDF in Python

Python is een generieke programmeertaal die voor allerlei toepassingen kan worden gebruikt. Zo ook voor het uitlezen en analyseren van een PDF. We gaan met verschillende Python packages aan de slag om dit te doen. Doordat Python een open source programmeertaal is met een rijk ecosysteem, zijn er diverse packages die voor deze toepassingen te gebruiken zijn.

In deze blog gebruiken we de volgende packages:

  • pandas: voor het werken met data in tabelvorm.
  • PyPDF2: voor het uitlezen van een PDF.
  • tabula-py: voor het uitlezen van tabellen in een PDF naar een pandas DataFrame.

We gebruiken specifiek deze packages omdat de PDF de data direct bevat. Het kan ook voorkomen dat een PDF afbeeldingen van data bevat. Denk aan ingescande documenten. Ook hier zijn mogelijkheden voor met bijvoorbeeld zogeheten OCR-tools (Optical Character Recognition). Hier staan we in deze blog niet verder bij stil.

3. Importeren van packages en definiëren van constanten

Allereerst importeren we in Python de te gebruiken packages:

import sys
import PyPDF2
import tabula
import pandas as pd

print("Python:", sys.version)
print("PyPDF2:", PyPDF2.__version__)
print("tabula:", tabula.__version__)
print("pandas:", pd.__version__)

Output:

Python: 3.8.9 (tags/v3.8.9:a743f81, Apr  2 2021, 11:10:41) [MSC v.1928 64 bit (AMD64)]
PyPDF2: 3.0.1
tabula: 2.9.3
pandas: 1.3.3

Vervolgens stellen we de referentie in naar het bestandspad van de PDF waarmee we gaan werken:

FILEPATH_TRANSACTIONS_PDF = "data/analyze_pdf_in_python/transactions_20251231_landscape.pdf"

Dit hergebruiken we later.

3. PDF uitlezen met PyPDF2

Met package PyPDF2 kun je allerlei handelingen met PDF-bestanden vanuit Python uitvoeren. Denk naast uitlezen aan inkorten of samenvoegen van PDF-bestanden.

In onderstaande code gebruiken we PyPDF2 om de PDF te openen en het aantal pagina's uit te lezen. We verwijzen hierbij naar het bestandspad van de PDF.

reader = PyPDF2.PdfReader(FILEPATH_TRANSACTIONS_PDF)
count_pages = len(reader.pages)

print(count_pages)

Output:

28

We zien dat de PDF is uitgelezen, en inderdaad bestaat uit 28 pagina's.

4. Tabel op PDF-pagina uitlezen met tabula-py

We hebben in de screenshots van de PDF gezien dat iedere pagina data in tabelvorm bevat. Met package tabula-py kunnen we dit uitlezen.

Met onderstaande code doen we een poging om de data uit de eerste pagina uit te lezen:

  • Met de (read_pdf()) functie lezen we een pagina uit de PDF uit.
  • Met input_path verwijzen we naar de bestandslocatie van de PDF.
  • Met pages geven we het paginanummer op.

Hierbij krijgen we (indien aanwezig) de gevonden tabellen van de PDF-pagina terug. Dit kunnen er ook meerdere zijn.

tables = tabula.read_pdf(
    input_path=FILEPATH_TRANSACTIONS_PDF,
    pages=1,
)

print("Tables count on PDF page:", len(tables))
print("Shape of table:", tables[0].shape)
tables[0]

Output:

Tables count on PDF page: 1
Shape of table: (26, 5)
Unnamed: 0Unnamed: 1Unnamed: 2RekeningafschriftUnnamed: 3
0nannanRekeningnummerDatum afschriftAantal transacties
1ONDERNEMERSREKENINGnan12.34.56.78931/12/2025834
2VolgnummerBoekdatumOmschrijvingBedrag af (debet)Bedrag bij (credit)
3102/01/2024Factuur ZL342560nan603,9
4202/01/2024Factuur ZL797708943,3nan
5302/01/2024Factuur ZL634455237,3nan
6403/01/2024Factuur ZL146909603nan
7503/01/2024Factuur ZL951417nan703,4
8605/01/2024Factuur ZL675929nan426,3
9705/01/2024Factuur ZL946947776,8nan

We zien vanuit de output het volgende:

  • Er is één tabel uit de eerste pagina van de PDF uitgelezen.
  • Deze tabel is direct bruikbaar als pandas DataFrame.
  • Echter, de tabel bevat ook de algemene gegevens, die niet direct bij de tabel met financiële gegevens horen.
  • Hierdoor kloppen bijvoorbeeld ook de kolomnamen niet.

Als volgende stap gaan we diverse experimenten uitvoeren om met tabula-py precies de juiste gegevens te verkrijgen.

5. Verdieping: tabel op PDF-pagina uitlezen met tabula-py

We kunnen divese aanpassingen doen om met tabula-py de data op de gewenste manier uit te kunnen lezen. Dit bekijken we voor verschillende pagina's.

5.1. Uitlezen van de eerste pagina

We hebben gezien dat we de data van de eerste pagina in tabelvorm uit kunnen lezen, maar dat dit nog niet helemaal goed gaat.

Met onderstaande code gebruiken we het area argument om op de eerste pagina slechts een deel van de pagina uit te lezen. Hierin lezen we de hele pagina uit, maar pas vanaf 25% van de bovenkant:

top = 25
left = 0
bottom = 100
right = 100

tables = tabula.read_pdf(
    input_path=FILEPATH_TRANSACTIONS_PDF,
    pages=1,
    area=[top, left, bottom, right],
    relative_area=True,
)

print("Shape of table:", tables[0].shape)
tables[0]

Output:

Shape of table: (23, 7)
VolgnummerBoekdatumOmschrijvingBedrag af (debet)Unnamed: 0Bedrag bij (credit)Unnamed: 1
0102/01/2024Factuur ZL342560nannannan603,9
1202/01/2024Factuur ZL797708nan943,3nannan
2302/01/2024Factuur ZL634455nan237,3nannan
3403/01/2024Factuur ZL146909nan603nannan
4503/01/2024Factuur ZL951417nannannan703,4

We zien het volgende:

  • De algemene informatie wordt niet meer uitgelezen: dat gaat goed.
  • Er ontstaan alleen extra, lege, kolommen, wat niet gewenst is.

Een andere manier voor het overslaan van de algemene informatie laten we met onderstaande code zien. Daarbij gebruiken we selecties met iloc[] (integer-location based indexing), om alleen de gewenste data te verkrijgen.

tables = tabula.read_pdf(
    input_path=FILEPATH_TRANSACTIONS_PDF,
    pages=1,
)

df = tables[0].iloc[3:]
df.columns = tables[0].iloc[2]

df

Output:

Shape of table: (23, 5)
VolgnummerBoekdatumOmschrijvingBedrag af (debet)Bedrag bij (credit)
3102/01/2024Factuur ZL342560nan603,9
4202/01/2024Factuur ZL797708943,3nan
5302/01/2024Factuur ZL634455237,3nan
6403/01/2024Factuur ZL146909603nan
7503/01/2024Factuur ZL951417nan703,4

Dit ziet er goed uit. Deze methode kunnen we gebruiken voor data van de eerste pagina

5.2. Uitlezen van pagina's 2 en verder

De pagina's vanaf pagina 2 bevatten alleen rijen met financiële transacties, geen kolomnamen of andere details.

Met onderstaande code lezen we de tweede pagina uit.

tables = tabula.read_pdf(
    input_path=FILEPATH_TRANSACTIONS_PDF,
    pages=2,
)

print("Shape of table:", tables[0].shape)
tables[0]

Output:

Shape of table: (30, 5)
2421/01/2024Factuur ZL831783832,3Unnamed: 0
02521/01/2024Factuur ZL171775nan77,9
12622/01/2024Factuur ZL742540nan738,3
22723/01/2024Factuur ZL468213984,4nan
32823/01/2024Factuur ZL831750334,7nan
42926/01/2024Factuur ZL801904848,9nan

Hierin zien we dat het uitlezen goed gaat, behalve de eerste rij. Deze wordt gezien gebruikt voor de kolomnamen. Dit corrigeren we met onderstaande code:

tables = tabula.read_pdf(
    input_path=FILEPATH_TRANSACTIONS_PDF,
    pages=2,
    pandas_options={'header': None}
)

print("Shape of table:", tables[0].shape)
tables[0]

Output:

Shape of table: (31, 5)
01234
02421/01/2024Factuur ZL831783832,3nan
12521/01/2024Factuur ZL171775nan77,9
22622/01/2024Factuur ZL742540nan738,3
32723/01/2024Factuur ZL468213984,4nan
42823/01/2024Factuur ZL831750334,7nan

Hiermee voorkomen we dat de eerste rij op een pagina als kolomnamen wordt gebruikt.

Wanneer we deze code nu echter hergebruiken om de rijen van de laatste pagina (28) uit te lezen, zien we het volgende:

tables = tabula.read_pdf(
    input_path=FILEPATH_TRANSACTIONS_PDF,
    pages=28,
    pandas_options={'header': None}
)

print("Shape of table:", tables[0].shape)
tables[0]

Output:

---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_8420/2191584453.py in <module>
      5 )
      6 
----> 7 print("Shape of table:", tables[0].shape)
      8 tables[0]

IndexError: list index out of range

We krijgen een foutmelding. Kennelijk kan er op de laatste pagina geen tabel gevonden worden. Ondanks dat deze er weldegelijk staat. Dit kunnen we oplossen door van het eerder gebruikte area argument gebruik te maken:

top = 0
left = 0
bottom = 100
right = 100

tables = tabula.read_pdf(
    input_path=FILEPATH_TRANSACTIONS_PDF,
    pages=28,
    area=[top, left, bottom, right],
    relative_area=True,
    pandas_options={'header': None}
)

print("Shape of table:", tables[0].shape)
tables[0]

Output:

Shape of table: (5, 5)
01234
083029/12/2025Factuur ZL113965nan77,1
183129/12/2025Factuur ZL592938nan819,8
283231/12/2025Factuur ZL642481128nan
383331/12/2025Factuur ZL139523nan853,3
483431/12/2025Factuur ZL624240315,8nan

Door deze aanpassing kunnen we alsnog de tabel op de laatste pagina uitlezen.

6. Samenvoegen van code

We hebben tot nu toe code ontwikkeld voor:

  • Uitlezen van de PDF en het bepalen van het aantal pagina's
  • Uitlezen van de tabel met financiële transacties op de eerste pagina
  • Uitlezen van de tabel met financiële transacties op pagina's 2 en verder

Met onderstaande code hergebruiken we dit, om de transacties van alle pagina's om te kunnen zetten naar één pandas DataFrame. Daarin doen we het volgende:

  • Uitlezen van het aantal pagina's
  • Aanmaken van een leeg DataFrame voor de combinatie van alle data.
  • Met een [for-loop](https://datasciencepartners.nl/python-for-loop/ "for-loop") elk van de pagina's uitlezen en omzetten naar een DataFrame.
  • Toevoegen van elke tabel aan het eerder aangemaakte DataFrame.
# Read PDF pages count
reader = PyPDF2.PdfReader(FILEPATH_TRANSACTIONS_PDF)
count_pages = len(reader.pages)

# Create empty dataframe
df_all_pages = pd.DataFrame()
# Define PDF page area
top = 0
left = 0
bottom = 100
right = 100

# Iterate over all pages in PDF and read table content
for page_number in range(1, count_pages + 1):
    # Read tables on specific page
    tables = tabula.read_pdf(
        FILEPATH_TRANSACTIONS_PDF,
        pages=page_number,
        area=[top, left, bottom, right],
        relative_area=True,
        pandas_options={'header': None}
    )
    # First page is different
    if page_number == 1:
        df_current_page = tables[0].iloc[4:]
        column_names = tables[0].iloc[3]
    else:
        df_current_page = tables[0]
    # Set column names
    df_current_page.columns = column_names
    # Concatenate tables
    df_all_pages = pd.concat([df_all_pages, df_current_page], ignore_index=True)

# Show result
print("Shape of table:", df_all_pages.shape)
df_all_pages

Output:

Shape of table: (834, 5)
VolgnummerBoekdatumOmschrijvingBedrag af (debet)Bedrag bij (credit)
0102/01/2024Factuur ZL342560nan603,9
1202/01/2024Factuur ZL797708943,3nan
2302/01/2024Factuur ZL634455237,3nan
3403/01/2024Factuur ZL146909603nan
4503/01/2024Factuur ZL951417nan703,4

Het resultaat ziet er goed uit: we hebben alle 834 rijen vanuit de 28 pagina's uit de PDF uitgelezen.

7. Analyseren van de data

We hebben de data uitgelezen en het is nu beschikbaar vanuit een pandas DataFrame. Daarmee kunnen er gemakkelijk analyses op uitgevoerd worden. Ook kan het daarmee gemakkelijk worden opgeslagen in een ander formaar. Bijvoorbeeld met de to_csv() methode voor een CSV-bestand, of de to_sql() methode voor opslag in een SQL database.

We gaan een simpele analyse uitvoeren en een visualisatie maken. Hiervoor voeren we met onderstaande code eerst enkele voorbewerkingen uit.

  • We stellen voor enkele kolommnen de juiste datatypes in.
  • Voegen een kolom toe die het jaar en de maand van de boekdatum bevat.
# Set column data types
float_columns = [
    "Bedrag af (debet)",
    "Bedrag bij (credit)",
]
date_columns = [
    "Boekdatum",
]
for float_column in float_columns:
    df_all_pages[float_column] = df_all_pages[float_column].str.replace(pat=",", repl=".")
    df_all_pages[float_column] = df_all_pages[float_column].astype(float)
for date_column in date_columns:
    df_all_pages[date_column] = pd.to_datetime(df_all_pages[date_column])

# Add calculated columns
df_all_pages["Jaar-Maand"] = df_all_pages["Boekdatum"].dt.strftime("%Y-%m")

Vervolgens maken we voor de analyse een visualisatie aan. We willen de af- of bijgeboekte bedragen per maand inzichtelijk maken. Dit doen we met onderstaande code.

  • We groeperen per maand en aggregeren de boekingen.
  • We maken een staafgrafiek.
# Group by month and aggregate
df_by_month = (
    df_all_pages
    .groupby("Jaar-Maand")
    .agg(
        {
            "Bedrag af (debet)": "sum",
            "Bedrag bij (credit)": "sum",
        }
    )
)

# Plot result
df_by_month.plot(
    title="Bedrag af en bij per maand",
    kind="bar",
)

Output:
chart bij voorbeeld pdf analyseren in python

Met dit voorbeeld hebben we laten zien dat de uit de PDF uitgelezen transacties gemakkelijk zijn te analyseren en/of visualiseren met package pandas.

Om te onthouden

We hebben gezien dat we met Python en diverse packages PDF-bestanden met daarin data in tabelvorm uit kunnen lezen. Het is daarbij altijd wenselijk om voordat je daarmee aan de slag gaat te onderzoeken of je de data niet alsnog in een ander, gestructureerder, formaat kunt verkrijgen. Zoals een CSV- of JSON-bestand. Want zoals we ook hebben gezien kunnen er allerlei issues zijn die opgelost moeten worden. Bijvoorbeeld het ontbreken van kolomnamen, of pagina's die niet direct goed uitgelezen konden worden. Maar met wat uitzoek is voor ieder issue een oplossing te vinden, waardoor je alsnog gebruik kunt maken van data uit een PDF-bestand.

Wil je nog veel meer leren over visualisaties met Python?

Schrijf je dan in voor onze Python cursus voor data science, Python advanced training, onze machine learning cursus, of voor onze data science opleiding en leer met vertrouwen te programmeren en visualiseren in Python. Nadat je een van onze trainingen hebt gevolgd kun je zelfstandig verder aan de slag. Je kunt ook altijd even contact opnemen als je een vraag hebt.

Download één van onze opleidingsbrochures voor meer informatie

by: