Cách làm việc với dữ liệu PDF trong Python

Cách làm việc với dữ liệu PDF trong Python

Aspose.PDF FOSS cho Python biểu diễn siêu dữ liệu XMP của tài liệu PDF dưới dạng mô hình dữ liệu trong bộ nhớ được xây dựng từ các đối tượng XmpPacket, XmpField, XmpArray, XmpStruct và XmpProperty, với NamespaceProvider giải quyết tiền tố không gian tên thành URI. Điều này cho phép bạn đọc, tạo và ghi lại siêu dữ liệu có cấu trúc — tiêu đề, ngày tháng, danh sách từ khóa, trường tùy chỉnh — mà không cần viết tay RDF/XML. Thư viện này hoàn toàn Python và được cài đặt bằng lệnh dưới đây.

Hướng dẫn từng bước

Bước 1: Cài đặt gói

Cài đặt gói 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 .

Xác minh việc cài đặt bằng cách nhập XmpPacket và in ra thông báo xác nhận:

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

Bước 2: Nhập các lớp cần thiết

Nhập các lớp mô hình dữ liệu XMP và bộ giải quyết không gian tên:

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

Bước 3: Tạo một Packet và Đặt các Thuộc tính Đơn giản

XmpPacket() bắt đầu với một danh sách trường trống. set_value(prefix, name, value, uri=...) thiết lập hoặc thay thế một thuộc tính đơn giản, và get(prefix_or_uri, name) đọc lại nó như một XmpField; get chấp nhận cả tiền tố đã đăng ký hoặc URI không gian tên đầy đủ:

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"

Bước 4: Lưu các Giá trị Được Đánh kiểu

XmpPacket cung cấp các accessor tiện lợi có kiểu dữ liệu, chuyển đổi tới và từ dạng văn bản thuần mà XMP lưu trữ nội bộ: set_date/get_date, set_int/get_int, set_real/get_real, và set_bool/get_bool. Mỗi getter trả về None khi thuộc tính không tồn tại thay vì ném lỗi:

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

Bước 5: Lưu Văn bản Địa phương hoá và Mảng Được Sắp xếp

set_localized_text ghi một thuộc tính ngôn ngữ-thay thế (rdf:Alt) như dc:title trong một ngôn ngữ cụ thể, mặc định là "x-default". set_array ghi một mảng được sắp xếp (Seq), không sắp xếp (Bag), hoặc thay thế (Alt) từ một danh sách các giá trị thuần, và get_array đọc lại nó như một danh sách các chuỗi:

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

Bước 6: Xây dựng Giá trị có cấu trúc với XmpStruct

Một số thuộc tính XMP (bản ghi kích thước, mục lịch sử) là các giá trị có cấu trúc thay vì văn bản đơn giản. Tạo một giá trị bằng XmpStruct, thêm thành viên XmpField đối tượng với add, và đọc lại thành viên theo tên bằng get, sau đó gắn cấu trúc vào gói bằng 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))

Bước 7: Đăng ký Không gian tên XMP tùy chỉnh

NamespaceProvider đã được tải sẵn các không gian tên XMP tiêu chuẩn (Dublin Core, Adobe XMP, PDF và các namespace khác). Gọi register(prefix, uri) để thêm một ánh xạ tùy chỉnh — nó trả về chính nhà cung cấp để có thể chuỗi các lời gọi — sau đó gắn nhà cung cấp vào gói để quá trình tuần tự hoá có thể giải quyết tiền tố tùy chỉnh thành URI của nó:

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

Bước 8: Phân tích và Tuần tự hoá một Gói

XmpPacket.parse(data, provider=...) đọc dữ liệu gói XMP thô dưới dạng byte hoặc văn bản vào một XmpPacket. serialize() và to_bytes() đều tạo lại gói thành byte gói XMP:

xmp_bytes = packet.to_bytes()

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

Các vấn đề thường gặp và cách khắc phục

get() hoặc một getter được gõ trả về None mặc dù tôi vừa đặt thuộc tính

Xác nhận đối số prefix (hoặc URI) cho get/get_int/get_date/etc. khớp chính xác với những gì đã được truyền vào lời gọi set_* tương ứng — get khớp cả tiền tố của trường và URI không gian tên của nó, nhưng một tiền tố tùy chỉnh không khớp ở một lời gọi và một URI ở lời gọi khác sẽ bị bỏ lỡ.

Tiền tố không gian tên tùy chỉnh tạo ra đầu ra không đầy đủ khi được tuần tự hoá

Một tiền tố không phải là một trong các không gian tên XMP tiêu chuẩn (dc, xmp, pdf, và tương tự) cần hoặc một đối số uri= rõ ràng trong mỗi lời gọi set_*, hoặc một NamespaceProvider với tiền tố đó đã được đăng ký và gắn vào gói qua XmpPacket(namespace_provider=provider) trước khi gọi serialize()/to_bytes().

get_bool, get_int, hoặc get_real returns None cho một giá trị tôi biết đã được đặt

Các getter có kiểu này trả về None khi văn bản lưu không được phân tích thành kiểu mong đợi — ví dụ, get_int trên một thuộc tính có giá trị được đặt bằng set_value dưới dạng văn bản tự do thay vì set_int. Sử dụng setter có kiểu tương ứng (set_int, set_real, set_bool) để logic phân tích của getter khớp với quá trình ghi.

XmpPacket.parse raises ValueError trên một gói tin từ nguồn không đáng tin cậy

parse từ chối bất kỳ khai báo <!DOCTYPE hoặc <!ENTITY nào như một biện pháp bảo vệ đầu vào thù địch chống lại các cuộc tấn công XXE và billion-laughs. Một gói XMP hợp pháp không bao giờ cần DTD; xem ngoại lệ như một tín hiệu rằng luồng nguồn bị sai dạng hoặc không an toàn thay vì cố gắng vượt qua biện pháp bảo vệ.

get_array returns None thay vì một danh sách

get_array trả về None khi thuộc tính được đặt tên không tồn tại hoặc không được lưu dưới dạng XmpArray (ví dụ, nếu nó được thiết lập bằng set_value thay vì set_array). Sử dụng set_array khi ghi thuộc tính để giá trị được lưu khớp với dạng mà get_array mong đợi.

Câu hỏi thường gặp

Sự khác nhau giữa set_value và các setter có kiểu như set_int là gì?

set_value lưu bất kỳ value nào bạn truyền vào nguyên trạng. Các setter có kiểu (set_date, set_int, set_real, set_bool) chuyển đổi đầu vào sang dạng văn bản thuần mà XMP sử dụng nội bộ và đi kèm với getter có kiểu tương ứng để phân tích lại, vì vậy hãy sử dụng chúng khi bạn cần tính an toàn kiểu qua vòng lặp thay vì chuỗi thô.

Các loại XmpArray (Bag, Seq, Alt) khác nhau như thế nào?

Bag là một tập hợp các giá trị không có thứ tự, Seq là một danh sách có thứ tự, và Alt chứa các giá trị thay thế (thường là các phiên bản ngôn ngữ, như được set_localized_text sử dụng). Gửi loại mong muốn tới set_array(..., kind="Bag") hoặc xây dựng một XmpArray(kind=...) trực tiếp.

Tôi có thể đọc danh sách thô các thuộc tính trên một gói mà không cần biết trước tên của chúng không?

Có — lặp packet.fields, nó chứa mọi XmpField, XmpArray, và XmpProperty được thêm vào gói theo thứ tự chèn.

Tôi có cần một NamespaceProvider cho các không gian tên XMP chuẩn không?

Không. dc, xmp, pdf, và các tiền tố chuẩn khác được giải quyết tự động. Một NamespaceProvider chỉ cần thiết cho các tiền tố tùy chỉnh mà bạn tự tạo.

Các bộ định tính XmpProperty khác biệt như thế nào so với một XmpField đơn giản?

XmpProperty bao bọc một XmpField cơ bản cùng với danh sách các trường định tính (được thêm bằng add_qualifier), được dùng cho trường hợp hiếm hơn khi một thuộc tính cần siêu dữ liệu RDF bổ sung được gắn vào giá trị của nó, ngoài bộ định tính xml:lang mà XmpField.language đã bao phủ.

Xem thêm

 Tiếng Việt