kw-scrape: Engine, CLI und MCP

Diese Seite beschreibt die kw-scrape-Komponente im Detail. Die Einbettung ins Gesamtsystem (Beziehung zu ki-web, gemeinsames Architekturmuster, Schreib- und DRY-Regeln) steht auf der Seite /web-scraping.

Was kw-scrape macht

kw-scrape holt eine oder viele externe URLs, extrahiert den Hauptinhalt als Markdown plus strukturierte Metadaten und gibt das Ergebnis als JSON-serialisierbare Datenstruktur zurück. Das Paket ist in drei Schichten aufgeteilt: eine Engine-Library, ein klassisches CLI und ein MCP-Server für AI-Tools.

Stack

Bewusst nicht enthalten: JavaScript-Rendering. Dynamisch nachgeladener Inhalt wird in dieser Ausbaustufe nicht gesehen.

Drei Schnittstellen, eine Engine

SchichtPfadZugriff
Engine (Library)/var/www/scrape/direkter Python-Import: from kw_scrape.composition import Composition
CLI (scrape-cli)/var/www/cli/scrape/Wrapper /usr/local/bin/scrape-cli
MCP-Server/var/www/mcp/scrape/Wrapper /usr/local/bin/scrape (stdio JSON-RPC)

Die CLI- und MCP-Schichten sind dünne Adapter um dieselbe Engine. Geschäftslogik liegt einmalig in der Engine.

Tool-Surface

Die drei Tools sind in CLI und MCP semantisch identisch, nur die Aufrufform unterscheidet sich.

ToolZweckHauptargumente
fetch_url (CLI: fetch)Eine URL holen, Hauptinhalt plus Metadatenurl, want_markdown, want_text, include_raw_html
extract_html (CLI: extract)Markdown aus rohem HTML, ohne Netzwerk-Aufrufhtml, base_url, want_markdown, want_text
scrape_urls (CLI: batch)Viele URLs parallel, getrennte Erfolg- und Fehlerlistenurls, concurrency (1 bis 50), want_markdown, want_text

Rückgabe-Struktur (ScrapeResult)

Bei fetch_url und jedem Eintrag in scrape_urls.items:

CLI-Beispiele

Eine Seite holen

scrape-cli fetch https://lisa-sundermeyer.de
scrape-cli --format table --columns title,sitename,date,language fetch https://lisa-sundermeyer.de
scrape-cli fetch https://lisa-sundermeyer.de | jq -r '.markdown'

HTML aus stdin oder Datei extrahieren

cat seite.html | scrape-cli extract --base-url https://example.com/
scrape-cli extract --file seite.html --base-url https://example.com/

Batch mit Fehler-Trennung

printf '%s\n' \
  https://ki.karlkratz.com/hallo-welt \
  https://ki.karlkratz.com/mcp-demo \
  https://ki.karlkratz.com/missing \
  | scrape-cli batch -c 3 \
  | jq '{total, ok: (.items | length), fail: (.errors | length)}'

Pipeline: Root holen, interne Links folgen

scrape-cli fetch https://lisa-sundermeyer.de \
  | jq -r '.markdown' \
  | grep -oE '\(https://lisa-sundermeyer\.de/[^)#]+\)' \
  | tr -d '()' \
  | sort -u | head -5 \
  | scrape-cli --format plain --columns url,title batch -c 5

MCP-Integration in drei AI-CLIs

Der MCP-Server ist als kw-scrape in allen drei lokalen AI-CLIs registriert: Claude Code, Codex und qwen-code. Tool-Aufrufe laufen über stdio JSON-RPC durch /usr/local/bin/scrape.

Claude Code

// ~/.claude.json, je Projekt unter mcpServers
"kw-scrape": {
  "type": "stdio",
  "command": "/usr/local/bin/scrape",
  "args": [],
  "env": {}
}

Codex

# ~/.codex/config.toml
[mcp_servers.kw-scrape]
command = "/usr/local/bin/scrape"

qwen-code

// ~/.qwen/settings.json, top-level mcpServers
"kw-scrape": {
  "command": "/usr/local/bin/scrape",
  "args": []
}

Performance

Eine Seite kostet ungefähr 200 ms Fetch und 30 bis 50 ms Extraktion. Mit Concurrency 10 erreicht das CLI 30 bis 50 Seiten pro Sekunde, bis die Höflichkeit gegen den Zielserver greift. Die typische Decke ist nicht das Tool, sondern die Rate-Limits der Gegenseite.

Env-Variablen

VariableDefaultWirkung
KW_SCRAPE_TIMEOUT15.0HTTP-Timeout in Sekunden
KW_SCRAPE_RETRIES1Transport-Retries bei netzseitigen Fehlern
KW_SCRAPE_USER_AGENTkw-scrape/0.1 (+https://ki.karlkratz.com)User-Agent-Header
KW_SCRAPE_MAX_BYTES5000000Hartes Limit pro Response (5 MB)
KW_SCRAPE_CONCURRENCY10Default-Parallelität für Batch

Exit-Codes (CLI)

CodeBedeutung
0OK
1Generischer Fehler
2Usage-Fehler (argparse)
3HTTP 404
4Validierung oder Extract-Fehler
5Backend 5xx
6Transport-Fehler (DNS, Timeout, non-JSON)

Grenzen

Erweiterungspunkt: PlaywrightFetcher

Die FetcherPort-Schnittstelle ist genau eine Methode: fetch(url) plus fetch_many(urls, concurrency). Eine zukünftige Playwright-Implementierung lässt sich an dieser Stelle einhängen, ohne UseCases oder die anderen Adapter zu ändern. Der Composition-Root entscheidet, welcher Fetcher genutzt wird.

Wichtigste Pfade

PfadInhalt
/var/www/scrape/Engine kw-scrape, Library
/var/www/cli/scrape/CLI scrape-cli
/var/www/mcp/scrape/MCP-Server kw-scrape
/usr/local/bin/scrape-cliCLI-Wrapper
/usr/local/bin/scrapeMCP-Wrapper (stdio)
/etc/bash_completion.d/scrape-cliBash-Completion für das CLI