unternehmens-factsheet-pdf-generieren-handelsregister-api

Unternehmens-Factsheet als PDF mit der Handelsregister.ai API erstellen

14 Min. Lesezeit

In diesem Tutorial erfährst du Schritt für Schritt, wie du mit Python, ReportLab und der Handelsregister.ai API automatisiert ein ansprechendes PDF-Factsheet für Unternehmen generierst – inklusive praktischem Layout mit zwei Spalten für Stichwörter und Produkte.

Unternehmens-Factsheet als PDF mit der Handelsregister.ai API erstellen

In diesem Artikel erfährst Du Schritt für Schritt, wie Du mithilfe der Handelsregister.ai API ein übersichtliches Unternehmens-Factsheet als PDF erzeugst – inklusive Layout-Anpassungen, damit zwei wichtige Bereiche (Stichwörter und Produkte) nebeneinanderstehen. Wir nutzen als Beispiel die Firma KONUX GmbH, aber Du kannst das Skript leicht an jede andere Firma anpassen. Alles, was Du dazu benötigst, ist etwas Python-Erfahrung und das Paket ReportLab. Wie Du letzteres installierst, erfährst Du ebenfalls im Text.


1. Überblick: Was Du erreichen wirst

  • API-Abfrage: Wir nutzen die Handelsregister.ai-API, um Informationen über ein Unternehmen abzurufen. Du bekommst dabei ein JSON mit Firmenstatus, Kontaktdaten, Finanzkennzahlen und Management-Personal.
  • PDF-Erzeugung: Mit ReportLab generieren wir ein Factsheet in PDF-Form. Darin stehen alle Basisdaten, Stichwörter, Produkte & Dienstleistungen, Management sowie Finanzkennzahlen.
  • Layout: Die beiden Bereiche Stichwörter und Produkte & Dienstleistungen sollen nebeneinander in zwei Spalten erscheinen – zentriert, damit es optisch ansprechend aussieht.

2. API-Aufruf verstehen: Endpunkt und Parameter

Um die gewünschten Daten zu erhalten, brauchst Du den richtigen API-Endpunkt von handelsregister.ai. Für unsere Zwecke rufen wir:

GET https://handelsregister.ai/api/v1/fetch-organization

auf. Dort kannst Du per Query-Parametern bestimmen, welche Firma Du suchst und welche Detail-Daten Du benötigst:

  1. api_key: Dein API-Schlüssel (nie öffentlich machen!).
  2. q: Suchbegriff, z. B. "KONUX GmbH".
  3. feature: Welche Zusatzinformationen Du willst (z. B. financial_kpi, balance_sheet_accounts, profit_and_loss_account, related_persons, publications).
  4. ai_search: Aktiviert die KI-Suche („on-default“).

Ein typischer Aufruf könnte so aussehen (API-Key als Platzhalter):

GET https://handelsregister.ai/api/v1/fetch-organization
    ?api_key=YOUR_API_KEY
    &q=KONUX%20GmbH
    &feature=financial_kpi
    &feature=balance_sheet_accounts
    &feature=profit_and_loss_account
    &feature=related_persons
    &ai_search=on-default

Ersetzt dabei YOUR_API_KEY durch Deinen echten Schlüssel. Um diesen sicher zu halten, lädst Du ihn am besten aus einer Umgebungsvariable.


3. JSON-Antwort: Wie sehen die Daten aus?

Die API liefert Dir ein JSON-Objekt mit vielen Feldern. Für KONUX könnten das sein:

  • name, address, status, legal_form, registration – Basisinformationen.
  • keywords, products_and_services – Stichwörter und Angebote des Unternehmens.
  • financial_kpi – Liste mit Finanzdaten (z. B. Jahr, Umsatz, Bilanzsumme, Mitarbeiteranzahl).
  • related_persons – aktuelles und ehemaliges Management.
  • balance_sheet_accounts und profit_and_loss_account – (falls abgefragt) detaillierte Bilanzen und GuV.

Abhängig davon, welche features Du übergibst, kann Dein JSON kürzer oder umfangreicher sein.


4. Voraussetzungen: Python, requests und ReportLab installieren

Um die folgenden Schritte auszuführen, solltest Du zuerst sicherstellen, dass Du die benötigten Python-Bibliotheken installiert hast:

pip install requests reportlab
  • requests: Für den HTTP-Aufruf der Handelsregister.ai API.
  • reportlab: Zum Erzeugen und Formatieren von PDF-Dateien.

Außerdem solltest Du Deinen API-Key als Umgebungsvariable bereithalten, damit er nicht versehentlich im Code sichtbar wird.


5. Daten per Python-Requests abrufen

Ein erstes Minimalbeispiel zum Abfragen der Daten könnte so aussehen:

import requests
import os

API_KEY = os.getenv("HANDELSREGISTER_API_KEY", "YOUR_API_KEY_HERE")
base_url = "https://handelsregister.ai/api/v1/fetch-organization"
query = "KONUX GmbH"
features = ["related_persons", "financial_kpi", ...]

url = f"{base_url}?api_key={API_KEY}&q={query}"
for feat in features:
    url += f"&feature={feat}"
url += "&ai_search=on-default"

response = requests.get(url)
data = response.json()

Hiermit erhältst Du bereits ein Dictionary (data) mit allen angeforderten Feldern.


6. PDF-Erzeugung: Dein finales Skript

Im nächsten Schritt wandelst Du die abgerufenen Daten in ein optisch ansprechendes PDF um. Wir verwenden ReportLab und haben das Skript so angepasst, dass folgende Features enthalten sind:

  • Titel und Untertitel (Firmenname + Unternehmenszweck).
  • Basisinformationen (Adresse, Rechtsform, Register, Kontaktinfos usw.).
  • Zwei Spalten für Stichwörter und Produkte & Dienstleistungen, nebeneinander und zentriert.
  • Finanzkennzahlen in einer Tabelle.
  • Management (z. B. aktuelle Geschäftsführer).
  • Wasserzeichen auf jeder Seite.

Im Folgenden findest Du das komplette Skript unternehmens_factsheet.py, das Du direkt ausführen kannst. Beim Aufruf übergibst Du Deinen Suchbegriff (z. B. "KONUX GmbH") und den Namen der Ausgabedatei (z. B. konux_factsheet.pdf):

python unternehmens_factsheet.py "KONUX GmbH" konux_factsheet.pdf

unternehmens_factsheet.py

#!/usr/bin/env python3
# -----------------------------------------------------------------------------
#  unternehmens_factsheet.py
#  Erstellt ein 1-2 seitiges, optisch modernes Factsheet (PDF, A4 Hochformat)
#  anhand von Live-Daten aus der Handelsregister.ai-API. Alle Texte & Labels
#  auf Deutsch.
#
#  Aufruf:
#       python unternehmens_factsheet.py "Suchbegriff" ausgabe.pdf
# -----------------------------------------------------------------------------

import json
import sys
import locale
import os
from pathlib import Path
from typing import Any, List, Dict, Optional
import requests

from reportlab.lib import colors
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import cm, mm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import (
    SimpleDocTemplate,
    Paragraph,
    Spacer,
    Table,
    TableStyle,
    ListFlowable,
    ListItem,
    Flowable
)
from reportlab.pdfgen import canvas

# Farben & Layout
COLOR_PRIMARY_DARK = colors.HexColor("#003366")
COLOR_PRIMARY = colors.HexColor("#005EB8")
COLOR_PRIMARY_LIGHT = colors.HexColor("#E0F0FF")

COLOR_TEXT_DARK = colors.HexColor("#1A1A1A")
COLOR_TEXT_MEDIUM = colors.HexColor("#595959")
COLOR_TEXT_LIGHT = colors.HexColor("#8C8C8C")

COLOR_BACKGROUND_GREY = colors.HexColor("#F5F5F5")
COLOR_WHITE = colors.white
COLOR_BORDER = colors.HexColor("#D9D9D9")

PAGE_WIDTH, PAGE_HEIGHT = A4
MARGIN_V = 18 * mm
MARGIN_H = 15 * mm
CONTENT_WIDTH = PAGE_WIDTH - 2 * MARGIN_H
CONTENT_HEIGHT = PAGE_HEIGHT - 2 * MARGIN_V

WATERMARK_TEXT = "handelsregister.ai"

# Symbole
ICON_STATUS = "🏷️"
ICON_LEGAL = "⚖️"
ICON_REGISTER = "🏛️"
ICON_DATE = "📅"
ICON_ADDRESS = "📍"
ICON_WEBSITE = "🔗"
ICON_EMAIL = "📧"
ICON_PHONE = "📞"
ICON_KEYWORD = "🔑"
ICON_PRODUCT = "💡"
ICON_FINANCE = "💰"
ICON_MANAGEMENT = "👤"
ICON_EMPLOYEES = "👥"

def format_num(val: Any, decimals: int = 0, currency: str = "€") -> str:
    """Formatiert Zahlen im de-DE-Format mit Währungssymbol."""
    if val in (None, ""):
        return "–"
    try:
        val = float(val)
        try:
            locale.setlocale(locale.LC_NUMERIC, "de_DE.UTF-8")
            formatted_num = locale.format_string(f"%.{decimals}f", val, grouping=True)
        except locale.Error:
            formatted_num = f"{val:,.{decimals}f}".replace(",", "X").replace(".", ",").replace("X", ".")
        if currency:
            return f"{formatted_num} {currency}"
        return formatted_num
    except:
        return str(val)

def format_int(val: Any) -> str:
    """Formatiert Ganzzahlen im de-DE-Format."""
    if val in (None, ""):
        return "–"
    try:
        val = int(val)
        try:
            locale.setlocale(locale.LC_NUMERIC, "de_DE.UTF-8")
            return locale.format_string("%d", val, grouping=True)
        except locale.Error:
            return f"{val:,}".replace(",", ".")
    except:
        return str(val)

def safe(val: Any, default: str = "–") -> str:
    return default if val in (None, "", [], {}) else str(val)

def create_link(url: Optional[str], text: Optional[str] = None) -> str:
    text = text or url
    if not url or not text:
        return safe(text)
    if not url.startswith(("http://", "https://")):
        url = f"http://{url}"
    return f'<a href="{url}" color="{COLOR_PRIMARY.hexval()}">{text}</a>'

def create_mailto(email: Optional[str], text: Optional[str] = None) -> str:
    text = text or email
    if not email or not text:
        return safe(text)
    return f'<a href="mailto:{email}" color="{COLOR_PRIMARY.hexval()}">{text}</a>'

def address_block(addr: Dict[str, Any]) -> str:
    if not addr:
        return "–"
    parts = [
        f"{addr.get('street','')} {addr.get('house_number','')}".strip(),
        f"{addr.get('postal_code','')} {addr.get('city','')}".strip(),
        addr.get("state", ""),
        addr.get("country", "")
    ]
    return "<br/>".join([p for p in parts if p])

def draw_watermark(canvas_obj: canvas.Canvas, _doc) -> None:
    canvas_obj.saveState()
    canvas_obj.setFont('Helvetica', 8)
    canvas_obj.setFillColor(colors.lightgrey, alpha=0.4)
    # Oben rechts
    canvas_obj.drawRightString(PAGE_WIDTH - MARGIN_H / 2, PAGE_HEIGHT - MARGIN_V / 1.5, WATERMARK_TEXT)
    # Unten rechts
    canvas_obj.drawRightString(PAGE_WIDTH - MARGIN_H / 2, MARGIN_V / 2, WATERMARK_TEXT)
    canvas_obj.restoreState()

def fetch_data_from_api(query: str) -> Dict[str, Any]:
    API_KEY = os.getenv("HANDELSREGISTER_API_KEY", "YOUR_API_KEY_HERE")
    base_url = "https://handelsregister.ai/api/v1/fetch-organization"
    features = ["related_persons","financial_kpi","balance_sheet_accounts","profit_and_loss_account","publications"]
    ai_search = "on-default"

    from requests.utils import requote_uri
    url = f"{base_url}?api_key={API_KEY}&q={requote_uri(query)}"
    for feat in features:
        url += f"&feature={feat}"
    url += f"&ai_search={ai_search}"

    try:
        response = requests.get(url)
        response.raise_for_status()
        data = response.json()
        return data
    except requests.RequestException as e:
        print(f"Fehler bei der API-Abfrage: {e}")
        sys.exit(1)
    except ValueError as e:
        print(f"Fehler beim JSON-Parsing: {e}")
        sys.exit(1)

def build_factsheet(data: Dict[str, Any], out_file: Path) -> None:
    doc = SimpleDocTemplate(
        str(out_file),
        pagesize=A4,
        topMargin=MARGIN_V,
        bottomMargin=MARGIN_V,
        leftMargin=MARGIN_H,
        rightMargin=MARGIN_H,
        title=safe(data.get("name"), "Unternehmensprofil"),
        author="handelsregister.ai"
    )
    styles = getSampleStyleSheet()
    styles.add(ParagraphStyle(name='MainTitle', fontName='Helvetica-Bold', fontSize=22,
                             textColor=COLOR_PRIMARY_DARK, spaceAfter=2*mm, leading=26))
    styles.add(ParagraphStyle(name='SubTitle', fontName='Helvetica-Oblique', fontSize=11,
                             textColor=COLOR_TEXT_MEDIUM, spaceAfter=6*mm, leading=14))
    styles.add(ParagraphStyle(name='H2', fontName='Helvetica-Bold', fontSize=14,
                             textColor=COLOR_PRIMARY_DARK, spaceBefore=6*mm, spaceAfter=3*mm, keepWithNext=1))
    styles.add(ParagraphStyle(name='H3', fontName='Helvetica-Bold', fontSize=10,
                             textColor=COLOR_PRIMARY, spaceBefore=4*mm, spaceAfter=2*mm, keepWithNext=1))
    styles.add(ParagraphStyle(name='Body', fontName='Helvetica', fontSize=9,
                             textColor=COLOR_TEXT_DARK, leading=12, spaceAfter=2*mm))
    styles.add(ParagraphStyle(name='Small', fontName='Helvetica', fontSize=8,
                             textColor=COLOR_TEXT_LIGHT))
    styles.add(ParagraphStyle(name='ListItem', parent=styles['Body'], leftIndent=15, spaceAfter=1*mm))
    styles.add(ParagraphStyle(name='TableHeader', fontName='Helvetica-Bold', fontSize=8.5,
                             textColor=COLOR_WHITE, alignment=TA_CENTER, parent=styles['Small']))
    styles.add(ParagraphStyle(name='TableCell', fontName='Helvetica', fontSize=8.5,
                             textColor=COLOR_TEXT_DARK, alignment=TA_LEFT, parent=styles['Small']))
    styles.add(ParagraphStyle(name='TableCellRight', fontName='Helvetica', fontSize=8.5,
                             textColor=COLOR_TEXT_DARK, alignment=TA_RIGHT, parent=styles['Small']))
    styles.add(ParagraphStyle(name='TableCellCenter', fontName='Helvetica', fontSize=8.5,
                             textColor=COLOR_TEXT_DARK, alignment=TA_CENTER, parent=styles['Small']))
    styles.add(ParagraphStyle(name='IconLabel', fontName='Helvetica', fontSize=9,
                             textColor=COLOR_TEXT_MEDIUM, parent=styles['Body']))
    styles.add(ParagraphStyle(name='IconValue', fontName='Helvetica', fontSize=9,
                             textColor=COLOR_TEXT_DARK, parent=styles['Body']))

    story: List[Flowable] = []
    spacer_sm = Spacer(1, 3*mm)
    spacer_md = Spacer(1, 6*mm)
    spacer_lg = Spacer(1, 10*mm)

    # Titel
    story.append(Paragraph(safe(data.get("name"), "Unternehmen"), styles['MainTitle']))
    if data.get("purpose"):
        story.append(Paragraph(safe(data.get("purpose")), styles['SubTitle']))
    else:
        story.append(spacer_md)

    # Basisinformationen
    story.append(Paragraph("Basisinformationen", styles['H2']))
    reg = data.get("registration", {})
    contact = data.get("contact_data", {})
    addr = data.get("address", {})

    info_data = [
        [Paragraph(f"{ICON_STATUS} Status", styles['IconLabel']),
         Paragraph(safe(data.get("status")), styles['IconValue'])],
        [Paragraph(f"{ICON_LEGAL} Rechtsform", styles['IconLabel']),
         Paragraph(safe(data.get("legal_form")), styles['IconValue'])],
        [Paragraph(f"{ICON_REGISTER} Register", styles['IconLabel']),
         Paragraph(f"{safe(reg.get('register_type'))} {safe(reg.get('register_number'))} ({safe(reg.get('court'))})",
                   styles['IconValue'])],
        [Paragraph(f"{ICON_DATE} Gründung", styles['IconLabel']),
         Paragraph(safe(data.get("registration_date")), styles['IconValue'])],

        [Paragraph(f"{ICON_ADDRESS} Adresse", styles['IconLabel']),
         Paragraph(address_block(addr), styles['IconValue'])],
        [Paragraph(f"{ICON_WEBSITE} Webseite", styles['IconLabel']),
         Paragraph(create_link(contact.get("website")), styles['IconValue'])],
        [Paragraph(f"{ICON_EMAIL} E-Mail", styles['IconLabel']),
         Paragraph(create_mailto(contact.get("email")), styles['IconValue'])],
        [Paragraph(f"{ICON_PHONE} Telefon", styles['IconLabel']),
         Paragraph(safe(contact.get("phone_number")), styles['IconValue'])]
    ]

    max_rows = 4
    table_data = []
    col_widths = [
        3*cm, (CONTENT_WIDTH/2) - 3.5*cm, 
        0.5*cm, 
        3*cm, (CONTENT_WIDTH/2) - 3.5*cm
    ]

    for i in range(max_rows):
        row = []
        row.extend(info_data[i])
        row.append("")  # Spacer
        row.extend(info_data[i + max_rows])
        table_data.append(row)

    info_table = Table(table_data, colWidths=col_widths)
    info_table.setStyle(TableStyle([
        ('VALIGN', (0, 0), (-1, -1), 'TOP'),
        ('LEFTPADDING', (0, 0), (-1, -1), 0),
        ('RIGHTPADDING', (0, 0), (-1, -1), 0),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 1.5*mm)
    ]))
    story.append(info_table)
    story.append(spacer_md)

    # 2-Spalten Bereich: Stichwörter (links) & Produkte (rechts)
    keywords_flow: List[Flowable] = []
    products_flow: List[Flowable] = []

    if data.get("keywords"):
        keywords_flow.append(Paragraph(f"{ICON_KEYWORD} Stichwörter", styles['H3']))
        kw_items = [ListItem(Paragraph(safe(kw), styles['ListItem'])) for kw in data["keywords"] if kw]
        if kw_items:
            keywords_flow.append(ListFlowable(kw_items, bulletType='bullet', start='•', leftIndent=5*mm))

    if data.get("products_and_services"):
        products_flow.append(Paragraph(f"{ICON_PRODUCT} Produkte & Dienstleistungen", styles['H3']))
        pd_items = [ListItem(Paragraph(safe(prod), styles['ListItem'])) for prod in data["products_and_services"] if prod]
        if pd_items:
            products_flow.append(ListFlowable(pd_items, bulletType='bullet', start='•', leftIndent=5*mm))

    if keywords_flow or products_flow:
        story.append(Paragraph("Tätigkeit & Angebot", styles['H2']))
        col_w = (CONTENT_WIDTH / 2) - 5*mm
        two_col_data = [[keywords_flow, products_flow]]
        two_col_table = Table(two_col_data, colWidths=[col_w, col_w], hAlign='CENTER')
        two_col_table.setStyle(TableStyle([
            ('VALIGN', (0, 0), (-1, -1), 'TOP'),
        ]))
        story.append(two_col_table)
        story.append(spacer_md)

    # Finanzkennzahlen
    fin = []
    if isinstance(data.get("financial_kpi"), list):
        fin = data["financial_kpi"]
    elif isinstance(data.get("financial_kpi"), dict):
        for y, vals in data["financial_kpi"].items():
            if y.isdigit():
                fin.append({
                    "year": int(y),
                    "active_total": vals.get("balance_sum"),
                    "revenue": vals.get("revenue"),
                    "net_income": vals.get("profit"),
                    "employees": vals.get("employees")
                })

    fin = sorted(fin, key=lambda x: x.get("year", 0), reverse=True)[:5]
    if fin:
        story.append(Paragraph(f"{ICON_FINANCE} Finanzkennzahlen (letzte {len(fin)} Jahre)", styles['H2']))
        header = [
            Paragraph("Jahr", styles['TableHeader']),
            Paragraph("Gesamtvermögen", styles['TableHeader']),
            Paragraph("Umsatz", styles['TableHeader']),
            Paragraph("Jahresergebnis", styles['TableHeader']),
            Paragraph(f"{ICON_EMPLOYEES} Mitarbeiter", styles['TableHeader'])
        ]
        rows = [header]
        for row_fin in fin:
            year = row_fin.get("year")
            active_total = row_fin.get("active_total")
            revenue = row_fin.get("revenue")
            net_income = row_fin.get("net_income")
            employees = row_fin.get("employees")
            rows.append([
                Paragraph(str(year), styles['TableCellCenter']),
                Paragraph(format_num(active_total), styles['TableCellRight']),
                Paragraph(format_num(revenue), styles['TableCellRight']),
                Paragraph(format_num(net_income), styles['TableCellRight']),
                Paragraph(format_int(employees), styles['TableCellCenter']),
            ])

        col_widths_fin = [2*cm, 4.5*cm, 4.5*cm, 4.5*cm, 3*cm]
        total_width = sum(col_widths_fin)
        if total_width < CONTENT_WIDTH:
            scale = CONTENT_WIDTH / total_width
            col_widths_fin = [w*scale for w in col_widths_fin]

        fin_table = Table(rows, colWidths=col_widths_fin)
        fin_table.setStyle(TableStyle([
            ('BACKGROUND', (0, 0), (-1, 0), COLOR_PRIMARY),
            ('TEXTCOLOR', (0, 0), (-1, 0), COLOR_WHITE),
            ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
            ('GRID', (0, 0), (-1, -1), 0.5, COLOR_BORDER),
            ('LEFTPADDING', (0, 0), (-1, -1), 2*mm),
            ('RIGHTPADDING', (0, 0), (-1, -1), 2*mm),
            ('TOPPADDING', (0, 0), (-1, -1), 1.5*mm),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 1.5*mm),
            ('ROWBACKGROUNDS', (0, 1), (-1, -1), [COLOR_WHITE, COLOR_BACKGROUND_GREY]),
        ]))
        story.append(fin_table)
        story.append(spacer_md)

    # Management (aktuelles Management)
    rp = data.get("related_persons", {})
    mgmt = rp.get("current", []) if isinstance(rp, dict) else []

    if mgmt:
        story.append(Paragraph(f"{ICON_MANAGEMENT} Geschäftsführung", styles['H2']))
        header = [
            Paragraph("Name", styles['TableHeader']),
            Paragraph("Position", styles['TableHeader']),
            Paragraph("Seit", styles['TableHeader'])
        ]
        rows = [header]
        for person in mgmt:
            role_de = person.get("role", {}).get("de", {})
            position = safe(role_de.get("long"), "Geschäftsführung")
            start_date = safe(person.get("start_date"), "–")
            rows.append([
                Paragraph(safe(person.get("name")), styles['TableCell']),
                Paragraph(position, styles['TableCell']),
                Paragraph(start_date, styles['TableCellCenter'])
            ])

        col_widths_mgmt = [
            (CONTENT_WIDTH * 0.5) - 1.5*cm,
            (CONTENT_WIDTH * 0.5) - 1.5*cm,
            3*cm
        ]
        mgmt_table = Table(rows, colWidths=col_widths_mgmt)
        mgmt_table.setStyle(TableStyle([
            ('BACKGROUND', (0, 0), (-1, 0), COLOR_PRIMARY),
            ('TEXTCOLOR', (0, 0), (-1, 0), COLOR_WHITE),
            ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
            ('GRID', (0, 0), (-1, -1), 0.5, COLOR_BORDER),
            ('LEFTPADDING', (0, 0), (-1, -1), 2*mm),
            ('RIGHTPADDING', (0, 0), (-1, -1), 2*mm),
            ('TOPPADDING', (0, 0), (-1, -1), 1.5*mm),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 1.5*mm),
            ('ROWBACKGROUNDS', (0, 1), (-1, -1), [COLOR_WHITE, COLOR_BACKGROUND_GREY]),
        ]))
        story.append(mgmt_table)
        story.append(spacer_lg)

    # PDF generieren (mit Wasserzeichen)
    doc.build(story, onFirstPage=draw_watermark, onLaterPages=draw_watermark)

def main() -> None:
    if len(sys.argv) != 3:
        print('Aufruf: python unternehmens_factsheet.py "Suchbegriff" ausgabe.pdf')
        sys.exit(1)

    query_str = sys.argv[1]
    out_path = Path(sys.argv[2])

    data = fetch_data_from_api(query_str)

    try:
        build_factsheet(data, out_path)
        print(f"✓ Factsheet erzeugt: {out_path.resolve()}")
    except Exception as e:
        print(f"Fehler bei der PDF-Erstellung: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()

7. Fazit

Mit dieser finalen Version des Python-Skripts hast Du eine einfache Möglichkeit, Live-Daten aus der Handelsregister.ai API abzurufen und direkt zu einem ansprechenden Unternehmens-Factsheet im PDF-Format zu verarbeiten. Die Spalten für Stichwörter und Produkte & Dienstleistungen stehen nun nebeneinander und sind zentriert, während Du die anderen Bereiche wie Basisinformationen, Finanzkennzahlen und Management kompakt darunter anordnen kannst.

Wenn Du in Zukunft ein anderes Unternehmen abfragen möchtest, brauchst Du nur den Query-String anpassen, z. B. "OroraTech GmbH" statt "KONUX GmbH". Achte stets auf ausreichend Fehlerbehandlung und den Schutz Deines API-Keys (per Umgebungsvariable oder einem sicheren Secrets-Manager). Mit ein paar Erweiterungen kannst Du das Factsheet jederzeit ausbauen, z. B. um detaillierte Bilanzen oder GuV-Tabellen einzufügen, mehrere Seiten zu generieren oder ein eigenes Farbkonzept einzubinden.

Viel Erfolg beim Erstellen und Verteilen Deiner automatisierten PDF-Factsheets!