Datenblatt-Generierung: On-Demand und Batch-PDF-Erstellung
Dieser Artikel erklärt, wie wir Produktdatenblätter als PDFs generieren, sowohl on-demand (wenn Benutzer sie anfordern) als auch im Batch (Vorgenerierung für beliebte Produkte).
Das Problem: Erstellung von Produktdatenblättern
Jedes Produkt benötigt ein professionelles PDF-Datenblatt mit:
-
Produktname und Bildern
-
Technischen Spezifikationen, nach Kategorien gruppiert
-
Firmenbranding und Kontaktinformationen
-
Optimiertem Layout (einzelne Seite, ausgeglichene Spalten)
PDFs bei jeder Anfrage zu generieren, ist langsam (~2 Sekunden pro PDF). Das Vorgenerieren aller 65.000 SKUs verschwendet Speicherplatz und Zeit.
Die Lösung: Hybrider Ansatz
Wir verwenden zwei Generierungsmethoden:
On-demand: PDF generieren, wenn der Benutzer es anfordert (erstmalig)
Batch: PDFs für beliebte Produkte vorgenerieren (täglich nachts)
On-Demand-Generierung
URL-Struktur
/ds/<sku>.pdf
/ds/<sku>
Beide URLs generieren dasselbe PDF.
Anfrageablauf
@web.route("/ds/<sku>.pdf")
def datasheet(sku: str):
# Validate SKU
# ... (implementation details omitted)
Generierungsprozess
Schritt 1: Produktdaten abrufen
# Product name
name = expand_sku(sku)
# ... (implementation details omitted)
Schritt 2: Spalten ausbalancieren
Features werden auf 3 Spalten verteilt, um die Zeilenanzahl auszugleichen:
# Calculate lines per feature group
all_groups = []
for heading, f_items in features.items():
# ... (implementation details omitted)
Schritt 3: Bildhöhen berechnen
# Main image height (proportional to aspect ratio)
with Image.open(main_image_path) as img:
main_width, main_height = img.size
# ... (implementation details omitted)
Schritt 4: Abstandshalter berechnen
Fußzeile an den Seitenboden schieben:
available_height = 25.0 # cm
content_height = total_image_height + text_height_cm
spacer_height = max(0, available_height - content_height)
Schritt 5: HTML rendern
html = render_template(
"datasheet.html",
sku=sku,
# ... (implementation details omitted)
Schritt 6: PDF generieren
options = {
"page-size": "A4",
"enable-local-file-access": None,
"load-error-handling": "ignore",
"load-media-error-handling": "ignore",
"no-stop-slow-scripts": None
}
pdf_data = pdfkit.from_string(html, options=options)
Schritt 7: Nur erste Seite behalten
reader = PdfReader(BytesIO(pdf_data))
if len(reader.pages) > 1:
writer = PdfWriter()
writer.add_page(reader.pages[0])
output = BytesIO()
writer.write(output)
pdf_data = output.getvalue()
Leistung
Generierungszeit: ~2 Sekunden pro PDF
Caching: Kein Caching (immer aktuell)
Vorteil: Immer auf dem neuesten Stand mit den aktuellsten Produktdaten
Batch-Generierung
Zweck
PDFs für beliebte Produkte vorgenerieren, um die On-Demand-Last zu reduzieren.
Skriptspeicherort
scripts/utils/generate_datasheets.py
Änderungen nachverfolgen
Wir verfolgen Änderungen an den für jede SKU relevanten Abschnitten der productdb.json:
def get_sku_productdb_hash(sku: str) -> str:
"""Get hash of productdb sections relevant to this SKU."""
with open(PRODUCTDB_PATH, "r") as f:
# ... (implementation details omitted)
Priorisierung
Wir priorisieren SKUs nach Anfragehäufigkeit:
def load_popular_skus() -> List[str]:
"""Load popular SKUs from access logs."""
try:
# ... (implementation details omitted)
Generierungsstrategie
def batch_generate():
# Load hash cache
hash_cache = load_hash_cache()
# ... (implementation details omitted)
Zeitplanung
Die Batch-Generierung läuft nachts via cron:
0 2 * * * cd /home/ubuntu/manage && python scripts/utils/generate_datasheets.py
Speicherung
Lokal: /home/ubuntu/web-static/ds/<sku>.pdf
S3: s3://thinvent-web-static/ds/<sku>.pdf
CDN: Ausgeliefert via CloudFront
Template-Struktur
Das Datenblatt-Template verwendet ein 3-Spalten-Layout:
<div class="container">
<!-- Header with logo and product name -->
<div class="header">
<img src="logo.png">
<h1>{{ name }}</h1>
</div>
<!-- Main image -->
<img src="{{ images[0][1] }}" style="width: 9.5cm">
<!-- Thumbnails (up to 4) -->
<div class="thumbnails">
{% for name, url in images[1:5] %}
<img src="{{ url }}" style="width: 4.5cm">
{% endfor %}
</div>
<!-- Features in 3 columns -->
<div class="features">
<div class="column">
{% for heading, items in features1 %}
<h3>{{ heading }}</h3>
{% for name, value in items.items() %}
<div><strong>{{ name }}:</strong> {{ value }}</div>
{% endfor %}
{% endfor %}
</div>
<div class="column">
<!-- features2 -->
</div>
<div class="column">
<!-- features3 -->
</div>
</div>
<!-- Spacer to push footer down -->
<div style="height: {{ spacer_height }}cm"></div>
<!-- Footer with contact info -->
<div class="footer">
<p>www.thinvent.in | sales@thinvent.in | +91-124-4343177</p>
</div>
</div>
Konfiguration
Konstanten steuern das Layout:
DATASHEET_COLUMN_COUNT = 3
DATASHEET_HEADING_LINE_WEIGHT = 2 # Lines per heading
DATASHEET_FEATURE_NAME_MAX_LEN = 30 # Chars before wrapping
DATASHEET_FEATURE_VALUE_CHARS_PER_LINE = 40 # Chars per line
PDF_PAGE_SIZE = "A4"
Integrationspunkte
Produktseiten
Link zum Datenblatt:
<a href="/ds/{{ sku }}.pdf" target="_blank">Download Datasheet</a>
Google Shopping
Datenblätter im Produktfeed verlinkt:
<g:product_detail>
<g:section_name>Datasheet</g:section_name>
<g:attribute_name>PDF</g:attribute_name>
<g:attribute_value>https://www.thinvent.in/ds/{{ sku }}.pdf</g:attribute_value>
</g:product_detail>
E-Mail-Kampagnen
Datenblätter an Angebots-E-Mails angehängt.
Fehlerbehandlung
Ungültige SKU
if not check_sku(sku):
abort(422, description="Product not found.")
Generierungsfehler
try:
pdf_data = generate_datasheet_pdf(sku)
if pdf_data is None:
abort(500, description="PDF generation failed.")
except Exception as e:
logger.error(f"PDF generation failed for {sku}: {e}")
abort(500, description="PDF generation failed.")
Fehlende Bilder
try:
with Image.open(image_path) as img:
width, height = img.size
except Exception:
# Use default dimensions
width, height = 800, 600
Referenzen
Bibliotheken
Verwandte Artikel
-
Feature Extraction - Abrufen von Produktspezifikationen
-
Content AI Generation - Produktbeschreibungen
-
SKU Structure - Produktkennungen
Zusammenfassung
Die Datenblatt-Generierung verwendet einen hybriden Ansatz:
On-Demand:
-
✅ Generieren, wenn der Benutzer anfordert
-
✅ Immer aktuell
-
✅ Keine Speicherverschwendung
-
✅ ~2 Sekunden pro PDF
Batch:
-
✅ Beliebte Produkte vorgenerieren
-
✅ productdb-Änderungen nachverfolgen
-
✅ Nach Anfragehäufigkeit priorisieren
-
✅ Täglicher Cron-Job nachts
Prozess:
-
✅ Produktdaten abrufen (Name, Bilder, Features, Beschreibung)
-
✅ Features über 3 Spalten ausbalancieren
-
✅ Bildhöhen berechnen
-
✅ HTML-Template rendern
-
✅ PDF mit pdfkit generieren
-
✅ Nur erste Seite behalten
Speicherung:
-
✅ Lokal:
/home/ubuntu/web-static/ds/ -
✅ S3:
s3://thinvent-web-static/ds/ -
✅ CDN: CloudFront-Distribution
Dieser hybride Ansatz balanciert Aktualität (On-Demand) mit Leistung (Batch-Vorgenerierung).