Πώς να εργαστείτε με δεδομένα PDF στο Python

Πώς να εργαστείτε με δεδομένα PDF στο Python

Aspose.PDF FOSS για Python αντιπροσωπεύει τα μεταδεδομένα XMP ενός εγγράφου PDF ως ένα μοντέλο δεδομένων στη μνήμη που δημιουργείται από αντικείμενα XmpPacket, XmpField, XmpArray, XmpStruct και XmpProperty, με το NamespaceProvider να επιλύει τα πρόθεμα ονοματοχώρων σε URI. Αυτό σας επιτρέπει να διαβάζετε, να δημιουργείτε και να ξαναγράφετε δομημένα μεταδεδομένα — τίτλους, ημερομηνίες, λίστες λέξεων-κλειδιών, προσαρμοσμένα πεδία — χωρίς να γράφετε χειροκίνητα RDF/XML. Η βιβλιοθήκη είναι καθαρά Python και εγκαθίσταται με την παρακάτω εντολή.

Οδηγός βήμα προς βήμα

Βήμα 1: Εγκατάσταση του πακέτου

Εγκαταστήστε το Aspose.PDF FOSS πακέτο:

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

Επαληθεύστε την εγκατάσταση εισάγοντας το XmpPacket και εκτυπώνοντας ένα μήνυμα επιβεβαίωσης:

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

Βήμα 2: Εισαγωγή Απαιτούμενων Κλάσεων

Εισαγάγετε τις κλάσεις του μοντέλου δεδομένων XMP και τον επιλυτή ονοματοχώρου:

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

Βήμα 3: Δημιουργία Πακέτου και Ορισμός Απλών Ιδιοτήτων

XmpPacket() ξεκινά με μια κενή λίστα πεδίων. set_value(prefix, name, value, uri=...) ορίζει ή αντικαθιστά μια απλή ιδιότητα, και get(prefix_or_uri, name) την διαβάζει ξανά ως XmpField; get δέχεται είτε το καταχωρημένο πρόθεμα είτε το πλήρες 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"

Βήμα 4: Αποθήκευση Τυποποιημένων Τιμών

XmpPacket παρέχει τυποποιημένους βολικούς προσπελάτες που μετατρέπουν προς και από τη μορφή απλού κειμένου που το XMP αποθηκεύει εσωτερικά: set_date/get_date, set_int/get_int, set_real/get_real, και set_bool/get_bool. Κάθε getter επιστρέφει None όταν η ιδιότητα δεν υπάρχει αντί να προκαλεί εξαίρεση:

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"))

Βήμα 5: Αποθήκευση Τοπικοποιημένου Κειμένου και Ταξινομημένων Πινάκων

set_localized_text γράφει μια γλωσσική εναλλακτική (rdf:Alt) ιδιότητα όπως το dc:title σε συγκεκριμένη γλώσσα, προεπιλεγμένη σε "x-default". set_array γράφει έναν ταξινομημένο (Seq), αταξινόμητο (Bag), ή εναλλακτικό (Alt) πίνακα από απλή λίστα τιμών, και get_array τον διαβάζει ξανά ως λίστα συμβολοσειρών:

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"))

Βήμα 6: Δημιουργία δομημένων τιμών με XmpStruct

Ορισμένες ιδιότητες XMP (εγγραφές διαστάσεων, καταχωρήσεις ιστορικού) είναι δομημένες τιμές αντί για απλό κείμενο. Δημιουργήστε μία με XmpStruct, προσθέστε μέλος XmpField αντικείμενα με add, και διαβάστε ένα μέλος πίσω με το όνομα χρησιμοποιώντας get, στη συνέχεια συνδέστε τη δομή στο πακέτο με add:

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))

Βήμα 7: Καταχώριση προσαρμοσμένων χώρων ονομάτων XMP

NamespaceProvider είναι προφορτωμένο με τους τυπικούς χώρους ονομάτων XMP (Dublin Core, Adobe XMP, PDF και άλλους). Καλέστε το register(prefix, uri) για να προσθέσετε έναν προσαρμοσμένο χάρτη — επιστρέφει τον ίδιο τον παροχέα ώστε οι κλήσεις να μπορούν να αλυσιδωθούν — στη συνέχεια συνδέστε τον παροχέα σε ένα πακέτο ώστε η σειριοποίηση να μπορεί να επιλύσει το προσαρμοσμένο πρόθεμα στο URI του:

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")

Βήμα 8: Ανάλυση και σειριοποίηση ενός πακέτου

XmpPacket.parse(data, provider=...) διαβάζει ακατέργαστα bytes ή κείμενο πακέτου XMP σε ένα XmpPacket. Τα serialize() και to_bytes() αποδίδουν και τα δύο το πακέτο πίσω σε bytes πακέτου XMP:

xmp_bytes = packet.to_bytes()

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

Κοινά προβλήματα και διορθώσεις

get() ή ένας typed getter επιστρέφει None παρόλο που μόλις όρισα την property

Επιβεβαιώστε ότι το όρισμα prefix (ή URI) στο get/get_int/get_date/κλπ. ταιριάζει ακριβώς με αυτό που περάστηκε στην αντίστοιχη κλήση set_* — το get ταιριάζει τόσο με το πρόθεμα του πεδίου όσο και με το URI του namespace, αλλά ένα ασύμφωνο προσαρμοσμένο πρόθεμα σε μία κλήση και ένα URI στην άλλη θα αποτύχει.

Προσαρμοσμένο πρόθεμα χώρου ονομάτων παράγει ημιτελή έξοδο κατά τη σειριοποίηση

Ένα πρόθεμα που δεν ανήκει σε κανένα από τα τυπικά namespaces του XMP (dc, xmp, pdf κ.λπ.) απαιτεί είτε ένα ρητό όρισμα uri= σε κάθε κλήση set_*, είτε ένα NamespaceProvider με αυτό το πρόθεμα καταχωρημένο και προσαρτημένο στο πακέτο μέσω XmpPacket(namespace_provider=provider) πριν κληθεί το serialize()/to_bytes().

get_bool, get_int, ή get_real returns None για μια τιμή που ξέρω ότι έχει οριστεί

Αυτοί οι τυποποιημένοι getters επιστρέφουν None όταν το αποθηκευμένο κείμενο δεν αναλύεται ως ο αναμενόμενος τύπος — για παράδειγμα, get_int σε μια ιδιότητα της οποίας η τιμή ορίστηκε με set_value ως ελεύθερο κείμενο αντί για set_int. Χρησιμοποιήστε το αντίστοιχο τυποποιημένο setter (set_int, set_real, set_bool) ώστε η λογική ανάλυσης του getter να ταιριάζει με τη διαδρομή εγγραφής.

XmpPacket.parse raises ValueError σε ένα packet από μη αξιόπιστη πηγή

parse απορρίπτει οποιαδήποτε δήλωση <!DOCTYPE ή <!ENTITY ως άμυνα εχθρικής εισόδου ενάντια σε επιθέσεις τύπου XXE και «billion-laughs». Ένα νόμιμο πακέτο XMP δεν χρειάζεται ποτέ DTD· αντιμετωπίστε την εξαίρεση ως σήμα ότι η πηγή ροής είναι κακοδιαμορφωμένη ή μη ασφαλής, αντί να παρακάμπτετε την άμυνα.

get_array returns None αντί για λίστα

get_array επιστρέφει None όταν η ονομασμένη ιδιότητα είτε δεν υπάρχει είτε δεν αποθηκεύτηκε ως XmpArray (για παράδειγμα, αν ορίστηκε με set_value αντί για set_array). Χρησιμοποιήστε set_array κατά τη γραφή της ιδιότητας ώστε η αποθηκευμένη τιμή να ταιριάζει με τη μορφή που αναμένει το get_array.

Συχνές Ερωτήσεις

Ποια είναι η διαφορά μεταξύ του set_value και των typed setters όπως το set_int;

set_value αποθηκεύει ό,τι value περάσετε όπως είναι. Οι typed setters (set_date, set_int, set_real, set_bool) μετατρέπουν την είσοδό τους στη μορφή plain-text που χρησιμοποιεί το XMP εσωτερικά και συνδυάζονται με έναν αντίστοιχο typed getter που την αναλύει ξανά, οπότε χρησιμοποιήστε τα όταν χρειάζεστε ασφάλεια τύπου σε round-trip αντί για ακατέργαστες συμβολοσειρές.

Πώς διαφέρουν τα είδη XmpArray (Bag, Seq, Alt);

Bag είναι ένα μη ταξινομημένο σύνολο τιμών, το Seq είναι μια ταξινομημένη λίστα, και το Alt περιέχει εναλλακτικές τιμές (συνήθως εναλλακτικές γλώσσας, όπως χρησιμοποιείται από το set_localized_text). Περάστε το επιθυμητό είδος στο set_array(..., kind="Bag") ή δημιουργήστε ένα XmpArray(kind=...) απευθείας.

Μπορώ να διαβάσω τη ακατέργαστη λίστα ιδιοτήτων σε ένα πακέτο χωρίς να γνωρίζω εκ των προτέρων τα ονόματά τους;

Ναι — επανάλαβε packet.fields, το οποίο περιέχει κάθε XmpField, XmpArray και XmpProperty που προστέθηκαν στο πακέτο με τη σειρά εισαγωγής.

Χρειάζομαι ένα NamespaceProvider για τους τυπικούς χώρους ονομάτων XMP;

Όχι. Τα dc, xmp, pdf και τα άλλα τυπικά πρόθεμα επιλύονται αυτόματα. Ένα NamespaceProvider απαιτείται μόνο για προσαρμοσμένα πρόθεμα που δημιουργείτε εσείς.

Πώς διαφέρουν οι XmpProperty προσδιοριστές από ένα απλό XmpField;

XmpProperty τυλίγει ένα βασικό XmpField μαζί με μια λίστα πεδίων προσδιοριστών (προστέθηκαν με add_qualifier), που χρησιμοποιείται για την πιο σπάνια περίπτωση όπου μια ιδιότητα χρειάζεται επιπλέον μεταδεδομένα RDF προσαρτημένα στην τιμή της, πέραν του προσδιοριστή xml:lang που ήδη καλύπτεται από το XmpField.language.

Δείτε επίσης

 Ελληνικά