Wie man mit PDF-Daten in Python arbeitet

Wie man mit PDF-Daten in Python arbeitet

Aspose.PDF FOSS für Python stellt die XMP-Metadaten eines PDF-Dokuments als ein im Speicher befindliches Datenmodell dar, das aus XmpPacket, XmpField, XmpArray, XmpStruct und XmpProperty-Objekten aufgebaut ist, wobei NamespaceProvider Namespace-Präfixe in URIs auflöst. Das ermöglicht das Lesen, Erstellen und Umschreiben strukturierter Metadaten — Titel, Daten, Stichwortlisten, benutzerdefinierte Felder — ohne manuelles Schreiben von RDF/XML. Die Bibliothek ist reines Python und wird mit dem untenstehenden Befehl installiert.

Schritt-für-Schritt-Anleitung

Schritt 1: Paket installieren

Installieren Sie das Aspose.PDF FOSS-Paket:

git clone https://github.com/aspose-pdf-foss/Aspose-PDF-FOSS-for-Python.git
cd Aspose-PDF-FOSS-for-Python
pip install -e .

Überprüfen Sie die Installation, indem Sie XmpPacket importieren und eine Bestätigungsnachricht ausgeben:

from aspose_pdf import XmpPacket
print("aspose-pdf-foss-for-python is ready.")

Schritt 2: Erforderliche Klassen importieren

Importieren Sie die XMP-Datenmodellklassen und den Namensraumauflöser:

from aspose_pdf import (
    NamespaceProvider,
    XmpArray,
    XmpField,
    XmpPacket,
    XmpProperty,
    XmpStruct,
)

Schritt 3: Ein Packet erstellen und einfache Eigenschaften festlegen

XmpPacket() beginnt mit einer leeren Feldliste. set_value(prefix, name, value, uri=...) setzt oder ersetzt eine einfache Eigenschaft, und get(prefix_or_uri, name) liest sie als XmpField zurück; get akzeptiert entweder das registrierte Präfix oder die vollständige Namespace-URI:

from aspose_pdf import XmpPacket

packet = XmpPacket()
packet.set_value("dc", "title", "Quarterly Report")
packet.set_value(
    "dc", "creator", "Automation Pipeline",
    uri="http://purl.org/dc/elements/1.1/",
)

title_field = packet.get("dc", "title")
print(title_field.value)  # "Quarterly Report"

Schritt 4: Typisierte Werte speichern

XmpPacket bietet typisierte Komfortzugriffe, die von und in die von XMP intern gespeicherte Klartextform konvertieren: set_date/get_date, set_int/get_int, set_real/get_real und set_bool/get_bool. Jeder Getter gibt None zurück, wenn die Eigenschaft fehlt, anstatt eine Ausnahme zu werfen:

from datetime import datetime

packet.set_date("xmp", "CreateDate", datetime(2026, 7, 29, 9, 30))
packet.set_int("pdf", "PageCount", 42)
packet.set_real("custom", "ConfidenceScore", 0.97, uri="https://example.com/ns/custom/1.0/")
packet.set_bool("custom", "IsFinal", True, uri="https://example.com/ns/custom/1.0/")

print(packet.get_date("xmp", "CreateDate"))
print(packet.get_int("pdf", "PageCount"))
print(packet.get_real("custom", "ConfidenceScore"))
print(packet.get_bool("custom", "IsFinal"))

Schritt 5: Lokalisierte Texte und geordnete Arrays speichern

set_localized_text schreibt eine sprachalternierende (rdf:Alt) Eigenschaft wie dc:title in einer bestimmten Sprache, wobei "x-default" standardmäßig verwendet wird. set_array schreibt ein geordnetes (Seq), ungeordnetes (Bag) oder alternatives (Alt) Array aus einer einfachen Werteliste und get_array liest es als Liste von Zeichenketten zurück:

packet.set_localized_text("dc", "description", "Quarterly summary", lang="en")
packet.set_localized_text(
    "dc", "description", "Resumen trimestral",
    uri="http://purl.org/dc/elements/1.1/", lang="es",
)
print(packet.get_localized_text("dc", "description", lang="es"))

packet.set_array("dc", "subject", ["finance", "quarterly", "internal"], kind="Bag")
print(packet.get_array("dc", "subject"))

Schritt 6: Strukturierte Werte mit XmpStruct erstellen

Einige XMP-Eigenschaften (Dimensionsdatensätze, Verlaufseinträge) sind strukturierte Werte und keine einfachen Texte. Erstellen Sie einen mit XmpStruct, fügen Sie Mitglied XmpField Objekte mit add hinzu und lesen Sie ein Mitglied anhand des Namens mit get aus, dann hängen Sie die Struktur mit add an das Paket an:

dimensions = XmpStruct()
dimensions.add(XmpField(prefix="stDim", name="w", value="612"))
dimensions.add(XmpField(prefix="stDim", name="h", value="792"))
dimensions.add(XmpField(prefix="stDim", name="unit", value="pt"))

print(dimensions.get("w").value)  # "612"

packet.add(XmpField(prefix="xmpTPg", name="MaxPageSize", value=dimensions))

Schritt 7: Benutzerdefinierte XMP-Namensräume registrieren

NamespaceProvider ist mit den Standard-XMP-Namensräumen (Dublin Core, Adobe XMP, PDF und weitere) vorbelegt. Rufen Sie register(prefix, uri) auf, um eine benutzerdefinierte Zuordnung hinzuzufügen—sie gibt den Provider selbst zurück, sodass Aufrufe verkettet werden können—und hängen Sie dann den Provider an ein Paket, damit die Serialisierung das benutzerdefinierte Präfix in seine URI auflösen kann:

from aspose_pdf import NamespaceProvider, XmpPacket

provider = NamespaceProvider()
provider.register("custom", "https://example.com/ns/custom/1.0/")

packet = XmpPacket(namespace_provider=provider)
packet.set_value("custom", "batch_id", "run-2026-07-29")

Schritt 8: Ein Paket parsen und serialisieren

XmpPacket.parse(data, provider=...) liest rohe XMP-Paket-Bytes oder Text in ein XmpPacket. serialize() und to_bytes() rendern das Paket beide zurück in XMP-Paket-Bytes:

xmp_bytes = packet.to_bytes()

restored = XmpPacket.parse(xmp_bytes)
print(restored.get("dc", "title").value)

Häufige Probleme und Lösungen

get() oder ein typisierter Getter zurückgibt None obwohl ich die Eigenschaft gerade gesetzt habe

Bestätigen Sie, dass das prefix-Argument (oder URI) für get/get_int/get_date/etc. exakt dem entspricht, was an den entsprechenden set_*-Aufruf übergeben wurde — get prüft sowohl den Präfix des Feldes als auch dessen Namespace-URI, aber ein nicht übereinstimmender benutzerdefinierter Präfix in einem Aufruf und ein URI im anderen führen zu einem Fehlmatch.

Benutzerdefinierter Namespace-Präfix erzeugt unvollständige Ausgabe bei Serialisierung

Ein Präfix, das nicht zu den Standard-XMP-Namespaces gehört (dc, xmp, pdf usw.), benötigt entweder ein explizites uri=-Argument bei jedem set_*-Aufruf oder ein NamespaceProvider, bei dem dieser Präfix registriert und dem Paket über XmpPacket(namespace_provider=provider) zugewiesen wurde, bevor serialize()/to_bytes() aufgerufen werden.

get_bool, get_int, oder get_real returns None für einen Wert, von dem ich weiß, dass er gesetzt ist

Diese typisierten Getter geben None zurück, wenn der gespeicherte Text nicht in den erwarteten Typ geparst werden kann — zum Beispiel get_int bei einer Eigenschaft, deren Wert mit set_value als Freitext statt mit set_int gesetzt wurde. Verwenden Sie den entsprechenden typisierten Setter (set_int, set_real, set_bool), damit die Parsing-Logik des Getters dem Schreibpfad entspricht.

XmpPacket.parse raises ValueError bei einem Paket aus einer nicht vertrauenswürdigen Quelle

parse verwirft jede <!DOCTYPE- oder <!ENTITY-Deklaration als Schutzmaßnahme gegen feindliche Eingaben (XXE und Billion-Laughs-Angriffe). Ein legitimes XMP-Paket benötigt niemals ein DTD; behandeln Sie die Ausnahme als Hinweis darauf, dass der Quellstrom fehlerhaft oder unsicher ist, anstatt die Schutzmaßnahme zu umgehen.

get_array returns None statt einer Liste

get_array gibt None zurück, wenn die benannte Eigenschaft entweder nicht existiert oder nicht als XmpArray gespeichert wurde (z.B. wenn sie mit set_value anstelle von set_array gesetzt wurde). Verwenden Sie set_array, wenn Sie die Eigenschaft schreiben, damit der gespeicherte Wert der von get_array erwarteten Struktur entspricht.

Häufig gestellte Fragen

Was ist der Unterschied zwischen set_value und den typisierten Settern wie set_int?

set_value speichert alles, was value Sie übergeben, unverändert. Die typisierten Setter (set_date, set_int, set_real, set_bool) konvertieren ihre Eingabe in die reine Textform, die XMP intern verwendet, und passen zu einem entsprechenden typisierten Getter, der sie wieder einliest. Verwenden Sie sie also, wenn Sie Rundweg-Typensicherheit benötigen statt roher Zeichenketten.

Wie unterscheiden sich die XmpArray-Typen (Bag, Seq, Alt)?

Bag ist eine ungeordnete Menge von Werten, Seq ist eine geordnete Liste und Alt enthält alternative Werte (meist Sprachalternativen, wie sie von set_localized_text verwendet werden). Übergeben Sie den gewünschten Typ an set_array(..., kind="Bag") oder erstellen Sie ein XmpArray(kind=...) direkt.

Kann ich die rohe Liste von Eigenschaften eines Pakets auslesen, ohne ihre Namen im Voraus zu kennen?

Ja — iterieren Sie packet.fields, das jedes XmpField, XmpArray und XmpProperty enthält, die in Einfügereihenfolge zum Paket hinzugefügt wurden.

Brauche ich ein NamespaceProvider für die standardmäßigen XMP-Namensräume?

Nein. dc, xmp, pdf und die anderen Standardpräfixe werden automatisch aufgelöst. Ein NamespaceProvider wird nur für benutzerdefinierte Präfixe benötigt, die Sie selbst erfinden.

Wie unterscheiden sich XmpProperty-Qualifizierer von einem einfachen XmpField?

XmpProperty umschließt ein Basis-XmpField zusammen mit einer Liste von Qualifikator-Feldern (hinzugefügt mit add_qualifier), die für den selteneren Fall verwendet wird, in dem eine Eigenschaft selbst zusätzliche RDF-Metadaten an ihrem Wert benötigt, über den xml:lang-Qualifizierer hinaus, den XmpField.language bereits abdeckt.

Siehe auch

 Deutsch