Web-Scraping im Karl-Kratz-System
Diese Seite beschreibt, wie Web-Scraping unter ki.karlkratz.com eingebettet ist: die beiden fachlichen Bausteine ki-web und kw-scrape, ihre Schnittstellen und das gemeinsame Architekturmuster dahinter.
Die Bausteine
ki-web
Verwaltet die Seiten dieser Domain (Slug, Titel, Meta-Description, HTML-Content). Die Geschäftslogik (Slug-Regex, HTML-Sanitization, Längen-Limits) liegt einmalig in der PHP-Schicht unter /api/pages und schreibt nach Postgres. Alle weiteren Zugriffsformen sind dünne Adapter über diese eine API.
kw-scrape
Eine eigenständige Python-Engine. Sie holt externe URLs mit httpx ab, extrahiert mit trafilatura den Hauptinhalt plus Metadaten (Titel, Autor, Datum, Sprache, Sitename) und gibt eine ScrapeResult-Datenstruktur zurück. JavaScript-gerenderte Seiten werden in dieser Ausbaustufe bewusst nicht unterstützt, weil dafür Playwright nötig wäre und der zusätzliche Aufwand sich für die aktuellen Anwendungsfälle nicht rechnet.
Die Schnittstellen-Klassen
Jeder Baustein wird über dieselbe Logik aus mehreren Richtungen bedient. Die Klassen sind komplementär und adressieren unterschiedliche Aufrufer.
| Klasse | Wer ruft auf | ki-web | kw-scrape |
|---|---|---|---|
| HTTP-API | Browser, andere Server | /api/pages (PHP) | noch nicht exponiert |
| CLI | Mensch am Terminal, Skripte, CI | ki-web-cli | scrape-cli |
| MCP-Server | Claude Code, Codex, qwen-code | ki-web | in Planung |
Architekturmuster
Beide Codebasen folgen dem gleichen DDD-Hexagonal-Schnitt mit drei Schichten.
- Domain: reine Datenstrukturen (Page, ScrapeResult, RawFetch, Extracted) und domänenspezifische Fehler. Kennt weder HTTP noch ein Framework.
- Application: Ports als Python-Protocols (PagesPort, FetcherPort, ExtractorPort) und Use Cases, die die Operationen orchestrieren.
- Infrastructure: die Adapter. PdoPageRepository für Postgres, HttpxFetcher für das Web, TrafilaturaExtractor für die HTML-Analyse, JsonHttpClient für die /api/pages-Aufrufe.
Die Application-Schicht spricht ausschließlich mit Ports. Konkrete Adapter werden in einem Composition-Root injiziert, sodass Tests den Fetcher gegen einen FakeFetcher tauschen können, ohne das Netzwerk zu berühren. Die gleiche Technik erlaubt, später eine PlaywrightFetcher-Implementierung der FetcherPort hinterzulegen, ohne die Use Cases zu ändern.
DRY-Schnitt: wo die Wahrheit lebt
Geschäftsregeln existieren genau einmal. Für ki-web liegen sie in der PHP-API. Für kw-scrape im Python-Paket unter /var/www/scrape/. CLI und MCP sind Adapter über diese Engines. Wenn eine Validierung ergänzt werden muss, geschieht das an einer Stelle, nicht parallel in mehreren Clients.
Output-Formate der CLIs
Sowohl ki-web-cli als auch scrape-cli kennen drei Output-Formate, gesteuert über --format.
- json: strukturierte Vollausgabe, Default. Geeignet für jq-Pipes und Skripte.
- table: Spaltenausgabe mit Header und Footer. Für die interaktive Shell.
- plain: ohne Dekoration. Eine Zeile pro Datensatz, Tab-separierte Spalten. Geeignet für xargs, cut und awk.
Über --columns slug,title,updated_at lassen sich in table und plain einzelne Felder herausziehen. In json hat das Flag keine Wirkung, weil dort die volle Struktur ohnehin verfügbar ist.
Beispiele
ki-web
ki-web-cli list --search mcp --limit 5
ki-web-cli get hallo-welt
ki-web-cli --format plain --columns slug list
echo '<h1>Demo</h1>' | ki-web-cli create --slug demo \
--title "Demo" --meta-description "Test" --content-file -kw-scrape
scrape-cli fetch https://ki.karlkratz.com/mcp-vs-api-vs-cli
scrape-cli fetch URL | jq -r '.markdown'
scrape-cli --format table --columns title,sitename,status fetch URL
scrape-cli batch --file urls.txt -c 20Was bewusst nicht im System ist
- Kein JavaScript-Rendering. Statische HTML-Seiten werden vollständig unterstützt, JS-gesteuerter Inhalt bleibt zunächst außen vor.
- Keine git-basierten Workflows. Pre-commit-Hooks, CI-Pipelines und PR-Reviews sind in diesem Projekt nicht vorgesehen.
- Keine doppelt gehaltenen Validierungsregeln. Sanitization bleibt in der PHP-Schicht, nicht in den Clients.
- Keine eigene HTTP-API für kw-scrape. Aktuell wird die Engine direkt als Python-Library importiert. Ein /api/scrape-Endpoint folgt erst, wenn ein nicht-Python-Konsument hinzukommt.
Wichtigste Pfade
| Pfad | Inhalt |
|---|---|
| /var/www/ki.karlkratz.com/src/ | PHP-Backend mit /api/pages |
| /var/www/mcp/ | MCP-Server ki-web (Python, stdio) |
| /var/www/cli/shared/ | Wiederverwendbare CLI-Infrastruktur (PresenterFactory, Streams, Exit-Codes, Help-Aliasse) |
| /var/www/cli/ki-web/ | CLI ki-web-cli |
| /var/www/scrape/ | Engine kw-scrape |
| /var/www/cli/scrape/ | CLI scrape-cli |
| /var/www/mcp.scrape/ | geplanter MCP-Server für kw-scrape |