Fitter MCP
Fitter — Webdaten für KI-Agenten
Fitter verwandelt jede Website oder API deklarativ in strukturiertes JSON. Eine JSON/YAML-Konfiguration beschreibt, wo die Daten liegen (HTTP-Anfrage, Headless-Browser, Datei, statischer Wert) und was extrahiert werden soll (JSON-Pfade, CSS-Selektoren, XPath). Kein Code, keine fragilen Scraping-Skripte.
🚀 Probieren Sie es im Browser aus — die echte Engine, kompiliert zu WebAssembly: Live-Beispiele, ein visueller Konfigurations-Builder, keine Installation.
Da Konfigurationen reine Daten sind, können LLMs sie erstellen. Der eingebaute MCP-Server ermöglicht es Claude Code, Claude Desktop oder jedem MCP-Client, Scraping-Pipelines auf Ihrem Rechner on demand zu schreiben und auszuführen:
"Hole die Top-5-HackerNews-Geschichten mit Titeln und Punktzahlen" → das Modell erstellt eine Fitter-Konfiguration, validiert sie, führt sie lokal aus und erhält sauberes JSON zurück.
Eine Engine, fünf Einsatzmöglichkeiten:
🤖 Fitter MCP | MCP-Server, der Fitter für Claude Code, Claude Desktop und jeden MCP-Client bereitstellt |
🧠 Fitter Agent | KI-gestützte CLI: natürliche Sprache → Konfiguration → ausgeführtes Ergebnis |
🖥 Fitter CLI | Konfigurationen lokal ausführen für Test/Debug/Heimgebrauch |
📦 Fitter Lib | Die Engine in Ihr eigenes Go-Programm einbetten |
⚙️ Fitter | Langlaufender Dienstmodus mit Zeitplanung und Benachrichtigungen |
Warum Fitter für KI-Agenten?
Deklarativ & nachvollziehbar — der Agent erstellt eine Konfiguration, die Sie lesen, speichern und erneut ausführen können, keinen Wegwerf-Code
Lokal zuerst — alle Abrufe erfolgen auf Ihrem Rechner; keine Drittanbieter-Scraping-API, keine Schlüssel, keine Abrechnung pro Anfrage
Alles inklusive — HTTP-Client, Headless-Browser (Playwright/Chromium/Docker), JSON/HTML/XML/XPath/PDF-Parsing, Paginierung, gecachte Referenzen, Host-Ratenbegrenzungen — in einer einzigen statischen Binärdatei
Wiederverwendbar — was der Agent heute erstellt, wird morgen zum Cron-Job oder zur Dienstkonfiguration
So verwenden Sie Fitter_MCP
Fitter MCP ist ein Model Context Protocol-Server (stdio-Transport), der es jedem MCP-Client — Claude Code, Claude Desktop, IDE-Assistenten, benutzerdefinierten Agenten — ermöglicht, Fitter-Konfigurationen auszuführen und strukturiertes JSON zurückzuerhalten.
Schnellstart (Claude Desktop — ein Klick)
Laden Sie fitter-mcp-<os>-<arch>.mcpb von der Release-Seite herunter und öffnen Sie es — Claude Desktop installiert den Server automatisch.
Schnellstart (Claude Code)
# 1. get the binary: download fitter_mcp_<version>-<os>-<arch> from the release page
# https://github.com/PxyUp/fitter/releases — or build it from source:
go build -o fitter_mcp ./cmd/mcp
# 2. register it once, available in every project
claude mcp add fitter -s user -- "$(pwd)/fitter_mcp"Dann fragen Sie einfach:
Hole die Top-5-HackerNews-Geschichten mit Titeln und Punktzahlen mit Fitter
Das Modell ruft fitter_config_reference auf, erstellt eine Konfiguration, prüft sie optional mit fitter_validate_config und führt sie über fitter_run aus — alle Datenabrufe erfolgen lokal auf Ihrem Rechner. Für eine fertige Pipeline probieren Sie examples/config_morning_briefing.json:
Führe examples/config_morning_briefing.json mit Fitter aus und gib mir das Briefing
In Claude Desktop registrieren
{
"mcpServers": {
"fitter": {
"command": "/path/to/fitter_mcp"
}
}
}Browser-Unterstützung (Playwright)
Das .mcpb-Bundle und die native Binärdatei werden ohne Browser ausgeliefert: HTTP-, statische und Datei-Connectors funktionieren sofort, aber Browser-Konfigurationen (der playwright-Connector) benötigen Playwrights Browser. Einige Möglichkeiten, sie zu erhalten:
Bei der ersten Verwendung (native Binärdatei /
.mcpb): Setzen Sie"install": trueim Playwright-Connector — Fitter lädt den Treiber + Browser passend zu seiner eingebautenplaywright-go-Version bei der ersten Verwendung herunter (einmalig, gecacht), sodass kein separater Installationsschritt erforderlich ist.Im Voraus (nativ, optional): Um den Download beim ersten Start zu vermeiden, installieren Sie die Browser vorab mit derselben
playwright-go-Version, gegen die Fitter gebaut ist (siehego.mod, aktuellv0.6100.0):go run github.com/mxschmitt/playwright-go/cmd/playwright@v0.6100.0 install # Linux: append --with-deps to also install the required OS librariesDie Version muss exakt mit
go.modübereinstimmen —playwright-goweigert sich, mit einem nicht passenden Treiber zu laufen. Führen Sie dann Konfigurationen ohne"install": trueaus.Docker: Verwenden Sie das
ghcr.io/pxyup/fitter-mcp:playwright-Image, das Chromium, Firefox und WebKit vorinstalliert enthält (kein"install": trueerforderlich).
Werkzeuge
Tool | Beschreibung |
| Führt eine inline übergebene Fitter-Konfiguration (JSON- oder YAML-String) aus und gibt die extrahierten Daten als JSON zurück. Akzeptiert einen optionalen |
| Wie |
| Wie |
| Ruft eine URL ab und gibt eine kompakte Strukturübersicht + Kandidaten-Selektoren/Pfade zurück (gjson-Pfade für JSON; wiederholte Element-/Listenzeilen-Selektoren für HTML), damit das Modell eine Konfiguration beim ersten Versuch erstellt, statt Selektoren zu raten und null zu erhalten. Erkennt clientgerenderte SPAs und kann sie in einem Headless-Browser |
| Validiert eine Konfiguration ohne Ausführung (Struktur, |
| Gibt eine komprimierte Referenz des gesamten Konfigurationsformats zurück (Connectors, Parser, Modell-/Feld-Schema, Platzhalter, Notifier, Referenzen, Limits) mit funktionierenden Beispielen, damit das Modell Konfigurationen ohne externe Dokumentation erstellen kann |
Die Referenz ist auch als MCP-Ressource fitter://config-reference für Clients verfügbar, die Ressourcen unterstützen.
Das Konfigurationsformat ist genau dasselbe wie für Fitter_CLI: ein Objekt der obersten Ebene mit item (erforderlich), limits und references. Notifier funktionieren ebenfalls (das Ergebnis wird zusätzlich an http/telegram/redis/file/console gesendet); trigger_config und http_server sind nur für den Dienstmodus und werden bei MCP-Aufrufen ignoriert.
Remote-/gehosteter Modus (streamable HTTP)
Standardmäßig kommuniziert fitter_mcp über stdio. Übergeben Sie --http, um den streamable HTTP transport zu bedienen — für einen gemeinsamen Team-Server, einen Container oder jede Remote-Bereitstellung:
# serve MCP at http://<host>:8080/mcp (health probe at /healthz)
FITTER_MCP_AUTH_TOKEN=my-secret fitter_mcp --http :8080
# register the remote endpoint in Claude Code
claude mcp add --transport http fitter http://localhost:8080/mcp --header "Authorization: Bearer my-secret"--http <addr>(UmgebungsvariableFITTER_MCP_HTTP_ADDR) — Listen-Adresse; stdio-Modus, wenn leerFITTER_MCP_AUTH_TOKEN— wenn gesetzt, muss jede/mcp-AnfrageAuthorization: Bearer <token>senden; ohne dies ist der Endpunkt nicht authentifiziert, also binden Sie ihn an localhost oder stellen Sie ihn hinter einen Proxy--stateless(UmgebungsvariableFITTER_MCP_STATELESS=true) — kein Pro-Sitzungs-Zustand, sodass Replikate hinter einem Load Balancer ohne Sticky Sessions stehen können
Der Server fährt bei SIGINT/SIGTERM sauber herunter.
Docker
Ein schlankes Multi-Arch-Image (linux/amd64 + linux/arm64) wird mit jedem Release ausgeliefert:
# hosted HTTP mode
docker run --rm -p 8080:8080 \
-e FITTER_MCP_HTTP_ADDR=:8080 \
-e FITTER_MCP_AUTH_TOKEN=my-secret \
ghcr.io/pxyup/fitter-mcp:latest
# or stdio mode, spawned by the MCP client
claude mcp add fitter -s user -- docker run --rm -i ghcr.io/pxyup/fitter-mcp:latestDas schlanke Image enthält nur die Fitter-Binärdatei und CA-Zertifikate: Server-/statische-/Datei-Connectors funktionieren, Browser-Connectors (chromium/docker/playwright) nicht.
Für browserbasierte Konfigurationen verwenden Sie die playwright-Variante, die Playwright mit Chromium, Firefox und WebKit bündelt (passend zur playwright-go-Version, gegen die Fitter gebaut ist, sodass kein "install": true in Konfigurationen erforderlich ist):
docker run --rm -i ghcr.io/pxyup/fitter-mcp:playwright # stdio mode
# per-release tag: ghcr.io/pxyup/fitter-mcp:vX.Y.Z-playwrightEs wird aus Dockerfile.mcp-playwright gebaut; bauen Sie mit --build-arg PLAYWRIGHT_BROWSERS=chromium für ein kleineres Chromium-only-Image.
OAuth2-Konten in Docker
Beide Images enthalten fitter_cli, sodass der einmalige OAuth2-Login im Container ausgeführt werden kann. Speichern Sie das Token auf einem Volume, das unter /tokens gemountet ist (im Image vorerstellt und beschreibbar), und teilen Sie es mit dem MCP-Server:
# one-time login, device flow: no ports needed — open the printed url on any device
docker run --rm -it -v fitter-tokens:/tokens --entrypoint fitter_cli \
ghcr.io/pxyup/fitter-mcp:latest \
auth --provider github --client-id <ID> --client-secret <SECRET> --token-file /tokens/github.json
# or browser flow (device flow not enabled for the app): publish the callback port and
# bind on 0.0.0.0 so the published port reaches the listener; the browser still visits 127.0.0.1
docker run --rm -it -p 8988:8988 -e FITTER_AUTH_LISTEN=0.0.0.0 \
-v fitter-tokens:/tokens --entrypoint fitter_cli ghcr.io/pxyup/fitter-mcp:latest \
auth --provider github --client-id <ID> --client-secret <SECRET> --token-file /tokens/github.json
# then run the MCP server with the same volume; configs reference "token_file": "/tokens/github.json"
# stdio mode (spawned by the MCP client, no port):
docker run --rm -i -v fitter-tokens:/tokens ghcr.io/pxyup/fitter-mcp:latest
# hosted HTTP mode (MCP endpoint on 8080, like the run examples above):
docker run --rm -p 8080:8080 -v fitter-tokens:/tokens \
-e FITTER_MCP_HTTP_ADDR=:8080 \
-e FITTER_MCP_AUTH_TOKEN=my-secret \
ghcr.io/pxyup/fitter-mcp:latestHinweis: 8988 ist nur für den einmaligen Browser-Flow-Login; der MCP-Server selbst benötigt im stdio-Modus keinen Port und im gehosteten HTTP-Modus nur 8080.
Angemeldete Browser-Sitzungen in Docker
Browser-Sitzungen benötigen das playwright-Image (das schlanke hat keine Browser). Der einmalige Login mit Anzeige benötigt ein Display, führen Sie ihn also auf dem Host aus und mounten Sie dann das Sitzungsverzeichnis in den Container (das Image erstellt vorab ein beschreibbares /sessions):
# on the host: log in once, save the session
fitter_cli browser-login --url https://example.com/login --storage-state ~/.fitter/sessions/example.json
# run the MCP server with the sessions dir mounted; configs reference "storage_state_file": "/sessions/example.json"
docker run --rm -i -v ~/.fitter/sessions:/sessions ghcr.io/pxyup/fitter-mcp:playwrightVerwenden Sie einen Bind-Mount (kein benanntes Volume): Der Container schreibt nach jedem Lauf aktualisierte Cookies zurück, sodass die Host-Kopie aktuell bleibt und jederzeit mit browser-login erweitert werden kann.
Das Volume muss für den Server beschreibbar bleiben: Rotierte Refresh-Tokens werden bei jeder Aktualisierung zurückgeschrieben.
Umgebungsvariablen
FITTER_PLUGINS - string[""] - Pfad für den Plugins-Ordner, wie das
--plugins-Flag von Fitter/Fitter_CLIFITTER_MCP_HTTP_ADDR - string[""] - Listen-Adresse für den Remote-Modus, wie
--httpFITTER_MCP_AUTH_TOKEN - string[""] - Bearer-Token, das den HTTP-Endpunkt schützt
FITTER_MCP_STATELESS - bool[false] - zustandsloser HTTP-Transport, wie
--stateless
Rezepte
Vollständige, getestete Konfigurationen, die die wichtigsten Muster zeigen. Alle laufen unverändert über Fitter_MCP (fitter_run_file), Fitter_CLI oder die Bibliothek – mehr in examples/.
Eine Seite ohne API scrapen und mit einer API anreichern
GitHub Trending hat keine offizielle API – scrapen Sie das HTML nach Repo-Slugs (html_attribute liest das href), und fächern Sie dann jeden einzelnen in die GitHub-REST-API mit {PL} auf:
examples/config_github_trending.json
{
"item": {
"connector_config": {
"response_type": "HTML",
"url": "https://github.com/trending",
"server_config": { "method": "GET", "headers": { "User-Agent": "Mozilla/5.0 (fitter demo)" } }
},
"model": {
"array_config": {
"root_path": "article.Box-row h2 a",
"length_limit": 5,
"item_config": {
"field": {
"type": "string",
"html_attribute": "href",
"generated": { "model": {
"type": "object",
"connector_config": {
"response_type": "json",
"url": "https://api.github.com/repos{PL}",
"server_config": { "method": "GET", "headers": { "User-Agent": "fitter-demo" } },
"null_on_error": true
},
"model": { "object_config": { "fields": {
"repo": { "base_field": { "type": "string", "path": "full_name" } },
"stars": { "base_field": { "type": "int", "path": "stargazers_count" } },
"language": { "base_field": { "type": "string", "path": "language" } }
} } }
} }
}
}
}
}
},
"limits": { "host_request_limiter": { "api.github.com": 2 } }
}[{"repo": "block/buzz", "stars": 6214, "language": "Rust"}, {"repo": "koala73/worldmonitor", "stars": 71179, "language": "TypeScript"}]Join über ein JSON-Feld mit einem Ausdruck
Wenn Array-Elemente Objekte sind, liegt der Join-Schlüssel in ihnen – extrahieren Sie ihn mit {{{FromExp=...}}} (expr-lang über fRes, das aktuelle Element). Buchsuche → Autorendetails, Suchanfrage über input bereitgestellt:
examples/config_book_authors.json
"url": "https://openlibrary.org/authors/{{{FromExp=fromJSON(fRes).author_key[0]}}}.json"./fitter_cli --path=examples/config_book_authors.json --input=dune[{"title": "Dune", "year": 1965, "author": {"name": "Frank Herbert", "born": "8 October 1920", "died": "11 February 1986"}}]Ergebnisse in eine lokale Datei schreiben
Das generierte Feld file_storage verwandelt Felder in Schreibvorgänge – die Top-5-Krypto-Coins werden an eine CSV angehängt, eine Zeile pro Element. Nackte {{{json.path}}}-Platzhalter lesen das aktuelle Element; {HUMAN_INDEX} stempelt den 1-basierten Rang (Elemente werden parallel verarbeitet, daher landen Anhänge in der Reihenfolge des Abschlusses – sortieren Sie nach der Rangspalte):
examples/config_crypto_csv.json
"file_storage": {
"content": "{HUMAN_INDEX},{{{name}}},{{{current_price}}},{{{price_change_percentage_24h}}}\n",
"file_name": "coins.csv",
"path": "/tmp/fitter-report",
"append": true
}$ sort -n /tmp/fitter-report/coins.csv
1,Bitcoin,64778,-2.3
2,Ethereum,1881.01,-3.4
3,Tether,0.999265,0Text aus einer PDF-Datei extrahieren
response_type: "pdf" verwandelt jedes abgerufene PDF in ein JSON-Dokument – {"text": "...", "pages": ["..."], "total_pages": N} – sodass reguläre JSON-Pfade (text, pages.0) und Ausdrücke darauf funktionieren. Das Bitcoin-Whitepaper, Seitenzahl plus eine gekürzte Einleitung:
{
"item": {
"connector_config": {
"response_type": "pdf",
"url": "https://bitcoin.org/bitcoin.pdf",
"server_config": { "method": "GET" }
},
"model": {
"object_config": {
"fields": {
"total_pages": { "base_field": { "type": "int", "path": "total_pages" } },
"intro": {
"base_field": {
"type": "string",
"path": "pages.0",
"generated": {
"calculated": {
"type": "string",
"expression": "trim(fRes[:100]) + \"...\""
}
}
}
}
}
}
}
}
}{"intro": "Bitcoin: A Peer-to-Peer Electronic Cash SystemSatoshi Nakamotosatoshin@gmx.comwww.bitcoin.orgAbstrac...", "total_pages": 9}Möglichkeiten zur Informationssammlung
Server – Parsen der Antwort von APIs oder HTTP-Anfragen (Verwendung von http.Client)
Browser – Emulation eines echten Browsers mit Chromium + Docker + Playwright/Cypress und Abrufen von DOM-Informationen
Statisch – Parsen eines statischen Strings als Daten
Formate, die geparst werden können
JSON – Parsen von JSON, um spezifische Informationen zu erhalten
XML – Parsen des XML-Baums, um spezifische Informationen zu erhalten
HTML – Parsen des DOM-Baums, um spezifische Informationen zu erhalten
XPath – Parsen des DOM-Baums, um spezifische Informationen zu erhalten, aber per XPath
PDF – Extrahieren von Text aus PDF-Dokumenten; der Inhalt wird als JSON
{"text": "...", "pages": ["..."], "total_pages": N}bereitgestellt, sodass reguläre JSON-Pfade wietextoderpages.0funktionieren
Als Bibliothek verwenden
go get github.com/PxyUp/fitterpackage main
import (
"fmt"
"github.com/PxyUp/fitter/lib"
"github.com/PxyUp/fitter/pkg/config"
"log"
"net/http"
)
func main() {
res, err := lib.Parse(&config.Item{
ConnectorConfig: &config.ConnectorConfig{
ResponseType: config.Json,
Url: "https://random-data-api.com/api/appliance/random_appliance",
ServerConfig: &config.ServerConnectorConfig{
Method: http.MethodGet,
},
},
Model: &config.Model{
ObjectConfig: &config.ObjectConfig{
Fields: map[string]*config.Field{
"my_id": {
BaseField: &config.BaseField{
Type: config.Int,
Path: "id",
},
},
"generated_id": {
BaseField: &config.BaseField{
Generated: &config.GeneratedFieldConfig{
UUID: &config.UUIDGeneratedFieldConfig{},
},
},
},
"generated_array": {
ArrayConfig: &config.ArrayConfig{
RootPath: "@this|@keys",
ItemConfig: &config.ObjectConfig{
Field: &config.BaseField{
Type: config.String,
},
},
},
},
},
},
},
}, nil, nil, nil, nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(res.ToJson())
}
Ausgabe:
{
"generated_array": ["id","uid","brand","equipment"],
"my_id": 6000,
"generated_id": "26b08b73-2f2e-444d-bcf2-dac77ac3130e"
}Verwenden Sie lib.ParseCtx(ctx, ...), um einen context.Context zu übergeben: Das Abbrechen bricht laufende Abrufe ab (HTTP-Anfragen, Headless-Browser, Docker-Container) und wendet Fristen durchgängig an. lib.Parse entspricht lib.ParseCtx(context.Background(), ...).
So verwenden Sie Fitter
Laden Sie die neueste Version von der Release-Seite herunter
oder lokal:
go run cmd/fitter/main.go --path=./examples/config_api.jsonArgumente
--path – string[""] – Pfad für die Konfiguration des Fitters
--url – string[""] – URL für die Konfiguration des Fitters
--verbose – bool[false] – Protokollierung aktivieren
--plugins – string[""] – Pfad für Plugins für Fitter
--log-level – enum["info", "error", "debug", "fatal"] – Protokollstufe festlegen (nur wenn verbose auf true gesetzt ist)
So verwenden Sie Fitter_CLI
Laden Sie die neueste Version von der Release-Seite herunter
oder lokal:
go run cmd/cli/main.go --path=./examples/cli/config_cli.jsonArgumente
--path – string[""] – Pfad für die Konfiguration des Fitter_CLI
--url – string[""] – URL für die Konfiguration des Fitter_CLI
--copy – bool[false] – Informationen in die Zwischenablage kopieren
--pretty – bool[true] – lesbares Ergebnis erzeugen (wirkt sich auch auf das Kopieren aus)
--verbose – bool[false] – Protokollierung aktivieren
--omit-error-pretty – bool[false] – reinen Wert liefern, wenn pretty ungültig ist
--plugins – string[""] – Pfad für Plugins für Fitter
--log-level – enum["info", "error", "debug", "fatal"] – Protokollstufe festlegen (nur wenn verbose auf true gesetzt ist)
--input – string[""] – Eingabewert für Formatierung angeben. Beispiele:
--input=\""124"\"--input=124--input='{"test": 5}'
./fitter_cli_${VERSION} --path=./examples/cli/config_cli.json --copy=truefitter_cli auth – ein OAuth2-Konto verbinden
Einmaliger interaktiver Login, der ein (Refresh-)Token für die OAuth2-Connector-Konfiguration speichert:
# device flow (default when the provider supports it): no callback, works headless
./fitter_cli_${VERSION} auth --provider github --client-id <ID> --client-secret <SECRET> --token-file ~/.fitter/tokens/github.json
# custom provider without preset
./fitter_cli_${VERSION} auth --auth-url https://.../authorize --token-url https://.../token --client-id <ID> --token-file ./token.jsonArgumente:
--provider – voreingestellt mit bekannten Endpunkten:
github|google|microsoft|gitlab|spotify--client-id / --client-secret – OAuth2-App-Anmeldedaten (einige Device-Flows funktionieren ohne Secret)
--token-file – wo das empfangene Token gespeichert wird (Berechtigungen 0600); verweisen Sie in
oauth2.token_fileauf denselben Pfad--flow –
auto(Device, falls verfügbar, sonst Browser),device(URL besuchen + Code eingeben) oderbrowser(localhost-Callback mit PKCE, Standard-Port 8988 – registrieren Siehttp://127.0.0.1:8988/callbackals App-Callback-URL)--scopes – durch Kommas getrennte Scopes
--auth-url/--token-url/--device-auth-url/--auth-style – Endpunkt-Überschreibungen für Anbieter ohne Voreinstellung
--port – int[8988] – Callback-Port für den Browser-Flow (env
FITTER_AUTH_PORT); mit dem Standardwert ist die beim Anbieter zu registrierende Callback-URLhttp://127.0.0.1:8988/callback--listen – Bind-Adresse für den Browser-Flow, Standard
127.0.0.1; setzen Sie0.0.0.0in einem Container, damit der veröffentlichte Port den Listener erreicht (envFITTER_AUTH_LISTEN)--redirect-url – Callback-URL, die beim Anbieter registriert ist, wenn sie von der Listen-Adresse abweicht, z. B. Docker-Portzuordnung (env
FITTER_AUTH_REDIRECT_URL)--no-browser – nur die Autorisierungs-URL ausgeben
Ausführung in Docker: siehe OAuth2-Konten in Docker.
Nach dem Login gibt der Befehl den gebrauchsfertigen oauth2-Konfigurationsblock aus. Der Connector aktualisiert das Zugriffstoken automatisch und schreibt rotierte Refresh-Tokens zurück in die Token-Datei, sodass der Login nur einmal benötigt wird.
fitter_cli browser-login – eine echte Login-Sitzung wiederverwenden
Für Websites ohne API/OAuth: Melden Sie sich einmal manuell in einem echten (sichtbaren) Browserfenster an – jedes Authentifizierungsschema funktioniert, einschließlich Passwörter, 2FA, SSO und Captchas – und speichern Sie die Sitzung für Headless-Scraping über storage_state_file:
./fitter_cli_${VERSION} browser-login --url https://example.com/login --storage-state ~/.fitter/sessions/example.json
# a browser window opens; log in, then press Enter in the terminal to save the sessionArgumente:
--url – zu öffnende Login-Seite (erforderlich)
--storage-state – wo die Sitzung gespeichert wird (Cookies + localStorage, Berechtigungen 0600); verweisen Sie in
playwright.storage_state_fileauf denselben Pfad (erforderlich)--browser – enum["Chromium", "FireFox", "WebKit"] Standard "Chromium"; verwenden Sie denselben Wert wie in der Scraping-Konfiguration – Websites können Sitzungen an den Browser-Fingerprint binden
--install – bool[false] – zuerst Playwright-Browser installieren
--indexeddb – bool[false] – IndexedDB in den Snapshot aufnehmen (Firebase Auth und Ähnliches)
Ein erneutes Ausführen des Befehls lädt zuerst den vorhandenen Zustand, sodass Sie eine Sitzung erweitern/aktualisieren können, ohne sich von Grund auf anzumelden. Der Scraping-Connector schreibt nach jedem Lauf auch aktualisierte Cookies zurück und hält die Sitzung am Leben, solange sie regelmäßig verwendet wird. Benötigt ein Display: Führen Sie diesen Befehl in Docker auf dem Host aus und mounten Sie die Datei – siehe Browser-Sitzungen in Docker.
Beispiele:
Server-Version HackerNews + Quotes + Guardian News – mit API + HTML + XPath-Parsing
Chromium-Version Guardian News + Quotes – mit HTML-Parsing + Browser-Emulation
Docker-Version Docker-Version: Guardian News + Quotes – mit HTML-Parsing + Browser aus Docker-Image
Playwright-Version Playwright-Version: Guardian News + Quotes – mit HTML-Parsing + Browser aus dem Playwright-Framework
Playwright-Version Playwright-Version: England Cities + Weather – mit HTML + XPath-Parsing + Browser aus dem Playwright-Framework
JSON-Version Paginierung generieren – mit statischem Connector zum Generieren eines Paginierungs-Arrays
Server-Version Aktuelle Zeit abrufen – Zeit von URL abrufen und formatieren
So verwenden Sie Fitter_Agent
Fitter Agent ist eine KI-gestützte CLI, die Claude verwendet, um natürliche Sprachbefehle in Fitter-Konfigurationen umzuwandeln und sie automatisch auszuführen.
Laden Sie die neueste Version von der Release-Seite herunter
oder lokal:
export ANTHROPIC_API_KEY=<your-anthropic-api-key>
go run cmd/agent/main.goArgumente
--api-key – string[""] – Anthropic-API-Schlüssel. Bevorzugen Sie die Umgebungsvariable
ANTHROPIC_API_KEY, damit der Schlüssel nicht in Ihrer Shell-Historie landet--model – string["claude-opus-4-8"] – zu verwendendes Claude-Modell
--effort – enum["low", "medium", "high", "xhigh", "max"] – Denkaufwand, Standard "high". Senken Sie ihn für schnellere/günstigere Konfigurationen, erhöhen Sie ihn für schwierigere Extraktionen
--verbose – bool[false] – Protokollierung aktivieren
--log-level – enum["info", "error", "debug", "fatal"] – Protokollstufe festlegen
--plugins – string[""] – Pfad für Plugins für Fitter
--chromium-limit – uint[0] – gleichzeitige Chromium-Instanzen begrenzen
--docker-limit – uint[0] – gleichzeitige Docker-Container begrenzen
--playwright-limit – uint[0] – gleichzeitige Playwright-Instanzen begrenzen
So funktioniert es
┌─────────────────────────────────────────────────────────────────┐
│ 1. User enters natural language request │
│ "Get top 5 HackerNews stories with titles and scores" │
│ ↓ │
│ 2. Claude returns a config in a schema-constrained response │
│ ↓ │
│ 3. Agent validates it; on failure the error is handed back │
│ to Claude to repair (up to 3 attempts) │
│ ↓ │
│ 4. Agent displays config and asks for confirmation │
│ ↓ │
│ 5. On confirmation, executes via lib.Parse() │
│ ↓ │
│ 6. Returns structured JSON result │
└─────────────────────────────────────────────────────────────────┘Eine Konfiguration verfeinern
Der Agent behält das Gespräch, sodass Sie nach der Generierung einer Konfiguration einfach sagen können, was geändert werden soll, anstatt die gesamte Anfrage zu wiederholen:
> Get top 3 HackerNews stories with titles and scores
refine> Only return 5 items and also include the article URLVerwenden Sie new, um die aktuelle Konfiguration zu verwerfen und eine neue Sitzung zu starten.
Interaktive REPL-Befehle
help – Hilfemeldung anzeigen
new/reset – aktuelle Konfiguration verwerfen und neu starten
clear – Bildschirm löschen
exit/quit/q – Agent beenden
Beispielsitzung
$ export ANTHROPIC_API_KEY=sk-ant-...
$ ./fitter_agent
╔══════════════════════════════════════════════════════════════╗
║ Fitter Agent - AI-Powered Data Extraction ║
╚══════════════════════════════════════════════════════════════╝
Describe what you want to extract. Follow-up messages refine the
previous config. Type 'help' for commands.
> Get top 3 HackerNews stories with titles and scores
┌─ Generated Fitter Config ───────────────────────────────────────
{
"item": {
"connector_config": {
"response_type": "json",
"url": "https://hacker-news.firebaseio.com/v0/topstories.json",
"server_config": { "method": "GET" }
},
"model": {
"array_config": {
"root_path": "@this",
"length_limit": 3,
"item_config": {
"fields": {
"id": { "base_field": { "type": "int" } },
"story": {
"base_field": {
"type": "int",
"generated": {
"model": {
"type": "object",
"connector_config": {
"response_type": "json",
"url": "https://hacker-news.firebaseio.com/v0/item/{PL}.json",
"server_config": { "method": "GET" }
},
"model": {
"object_config": {
"fields": {
"title": { "base_field": { "type": "string", "path": "title" } },
"score": { "base_field": { "type": "int", "path": "score" } }
}
}
}
}
}
}
}
}
}
}
}
}
}
└──────────────────────────────────────────────────────────────────
Execute this config? [y/n]: y
┌─ Result ────────────────────────────────────────────────────────
[
{
"id": 46740029,
"story": { "title": "Show HN: Open-source project", "score": 161 }
},
{
"id": 46737630,
"story": { "title": "Interesting article", "score": 237 }
},
{
"id": 46735644,
"story": { "title": "New technology release", "score": 192 }
}
]
└──────────────────────────────────────────────────────────────────
> exit
Goodbye!Beispielanfragen
Anfrage | Was es tut |
| Ruft aktuellen BTC-Preis ab |
| HTML-Scraping mit CSS-Selektoren |
| Verschachtelte API-Aufrufe |
| Einfache API-Extraktion |
| Web-Scraping |
Unterstützte Funktionen
Der Agent kann Konfigurationen generieren für:
JSON-APIs – REST-APIs mit GET/POST-Methoden
HTML-Scraping – Extraktion basierend auf CSS-Selektoren
XPath-Scraping – Extraktion basierend auf XPath
Verschachtelte API-Aufrufe – Details für jedes Element in einer Liste abrufen
Browser-Emulation – Playwright für JS-gerenderte Seiten
Formatierte Felder – URL-Vorlagen mit Platzhaltern
Array-Begrenzung – Ergebnisse auf N Elemente begrenzen
Konfiguration
Connector
Es ist die Art und Weise, wie Sie die Daten abrufen.
type ConnectorConfig struct {
ResponseType ParserType `json:"response_type" yaml:"response_type"`
Url string `json:"url" yaml:"url"`
Attempts uint32 `json:"attempts" yaml:"attempts"`
NullOnError bool `yaml:"null_on_error" json:"null_on_error"`
StaticConfig *StaticConnectorConfig `json:"static_config" yaml:"static_config"`
IntSequenceConfig *IntSequenceConnectorConfig `json:"int_sequence_config" yaml:"int_sequence_config"`
ServerConfig *ServerConnectorConfig `json:"server_config" yaml:"server_config"`
BrowserConfig *BrowserConnectorConfig `yaml:"browser_config" json:"browser_config"`
PluginConnectorConfig *PluginConnectorConfig `json:"plugin_connector_config" yaml:"plugin_connector_config"`
ReferenceConfig *ReferenceConnectorConfig `yaml:"reference_config" json:"reference_config"`
FileConfig *FileConnectorConfig `json:"file_config" yaml:"file_config"`
}NullOnError[false] – wenn auf true gesetzt, werden alle Fehler ignoriert
ResponseType – enum["HTML", "json", "xpath", "XML", "pdf"] – in welchem Format die Daten vom Connector kommen
Attempts – wie viele Versuche zum Abrufen der Daten durch den Connector verwendet werden
Url – definiert, welche Adresse angefragt werden soll. Wichtig: kann mit Injektion des übergeordneten Werts als String verwendet werden
https://api.open-meteo.com/v1/forecast?latitude={{{latitude}}}&longitude={{{longitude}}}&hourly=temperature_2m&forecast_days=1
Die Konfiguration kann eine der folgenden sein:
Beispiel:
{
"response_type": "xpath",
"attempts": 3,
"url": "https://openweathermap.org/find?q={PL}",
"browser_config": {
"playwright": {
"timeout": 30,
"wait": 30,
"install": false,
"browser": "Chromium"
}
}
}PluginConnectorConfig
Der Connector kann über das Plugin-System definiert werden. Dafür müssen Sie die folgenden Flags auf Fitter/Cli anwenden (Speicherort der Plugins):
... --plugins=./examples/plugin--plugins – sucht nach allen Dateien mit der Erweiterung ".so" im angegebenen Ordner (Unterordner ausgeschlossen)
type PluginConnectorConfig struct {
Name string `json:"name" yaml:"name"`
Config json.RawMessage `json:"config" yaml:"config"`
}{
"name": "connector",
"config": {
"name": "Elon"
}
}Name – Name des Plugins
Config – JSON-Konfiguration des Plugins
So erstellen Sie ein Plugin
Plugin erstellen
go build -buildmode=plugin -gcflags="all=-N -l" -o examples/plugin/connector.so examples/plugin/connector/connector.goStellen Sie sicher, dass Sie die Variable Plugin exportieren, die das Interface pl.ConnectorPlugin implementiert.
Beispiel für CLI:
https://github.com/PxyUp/fitter/blob/master/examples/cli/config_plugin.json#L5
Plugin-Beispiel:
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/PxyUp/fitter/pkg/config"
"github.com/PxyUp/fitter/pkg/logger"
"github.com/PxyUp/fitter/pkg/builder"
pl "github.com/PxyUp/fitter/pkg/plugins/plugin"
)
var (
_ pl.ConnectorPlugin = &plugin{}
Plugin plugin
)
type plugin struct {
log logger.Logger
Name string `json:"name" yaml:"name"`
}
func (pl *plugin) Get(ctx context.Context, parsedValue builder.Interfacable, index *uint32, input builder.Interfacable) ([]byte, error) {
return []byte(fmt.Sprintf(`{"name": "%s"}`, pl.Name)), nil
}
func (pl *plugin) SetConfig(cfg *config.PluginConnectorConfig, logger logger.Logger) {
pl.log = logger
if cfg.Config != nil {
err := json.Unmarshal(cfg.Config, pl)
if err != nil {
pl.log.Errorw("cant unmarshal plugin configuration", "error", err.Error())
return
}
}
}ReferenceConnectorConfig
Connector, der das Abrufen von vorab geladenen Daten aus references ermöglicht
type ReferenceConnectorConfig struct {
Name string `yaml:"name" json:"name"`
}Beispiel
https://github.com/PxyUp/fitter/blob/master/examples/cli/config_ref.json#L66
Name – Referenzname aus der references-Map
IntSequenceConnectorConfig
Verbesserte Version des Static-Connectors, die eine Integer-Sequenz als Ergebnis generiert
type IntSequenceConnectorConfig struct {
Start int `json:"start" yaml:"start"`
End int `json:"end" yaml:"end"`
Step int `json:"step" yaml:"step"`
}Start[0] – Startpunkt für die Generierung (eingeschlossen)
End[0] – Endpunkt für die Generierung (ausgeschlossen vom Endergebnis wie range in jeder Sprache)
Step[1] – Intervall für die Sequenz
Beispiel
{
"start": 0,
"end": 2
// Generate [0, 1]
}FileConnectorConfig
Connector-Typ, der Daten aus der angegebenen Datei abruft
type FileConnectorConfig struct {
Path string `yaml:"path" json:"path"`
UseFormatting bool `yaml:"use_formatting" json:"use_formatting"`
}Path – Dateipfad. Unterstützt formatting
UseFormatting[false] – formatting des Dateiinhalts verwenden oder nicht
StaticConnectorConfig
Connector-Typ, der Daten aus dem angegebenen String abruft
type StaticConnectorConfig struct {
Value string `json:"value" yaml:"value"`
Raw json.RawMessage `json:"raw" yaml:"raw"`
}Value – statischer String als Daten, kann HTML oder JSON sein
Raw – akzeptiert rohes JSON. Beispiel. Unterstützt auch formatting
Beispiel:
https://github.com/PxyUp/fitter/blob/master/examples/cli/config_static_connector.json#L5
{
"value": "[1,2,3,4,5]"
}ServerConnectorConfig
Connector-Typ, der Daten mit dem golang http.Client abruft (serverseitige Anfrage wie curl)
type ServerConnectorConfig struct {
Method string `json:"method" yaml:"method"`
Headers map[string]string `yaml:"headers" json:"headers"`
Timeout uint32 `yaml:"timeout" json:"timeout"`
JsonRawBody json.RawMessage `json:"json_raw_body" yaml:"json_raw_body"`
Body string `yaml:"body" json:"body"`
ErrorOnStatus bool `json:"error_on_status" yaml:"error_on_status"`
Proxy *ProxyConfig `yaml:"proxy" json:"proxy"`
OAuth2 *OAuth2Config `yaml:"oauth2" json:"oauth2"`
}Method – unterstützt alle HTTP-Methoden: GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD
Headers – vordefinierte Header für die Anfrage kann in Schlüssel/Wert injiziert werden
Timeout[sec] – Standard-Timeout 60 Sekunden oder der angegebene Wert
Body – Body der Anfrage, geparster Wert kann injiziert werden
JsonRawBody – Body der Anfrage im JSON-Format; Wert kann injiziert werden
ErrorOnStatus – optional, Standard
false. Wenntrue, wird ein HTTP-Antwortstatus>= 400als Abruffehler behandelt (durchläuftattempts/null_on_error), anstatt den Fehler-Body zu parsen – so können Sie einen fehlgeschlagenen Abruf von einem wirklich leeren Ergebnis unterscheiden. Wenn Sie es auffalselassen, bleibt das ursprüngliche Verhalten erhalten, bei dem der zurückgegebene Body geparst wird.Proxy – Proxy für die Anfrage einrichten config
OAuth2 – ein Zugriffstoken automatisch abrufen/aktualisieren und als
Authorization-Header senden config
Anfragen senden standardmäßig einen identifizierbaren
User-Agent(fitter (+https://github.com/PxyUp/fitter)); setzen Sie Ihren eigenenUser-AgentinHeaders, um ihn zu überschreiben.
Beispiel:
{
"method": "GET",
"proxy": {
"server": "http://localhost:8080",
"username": "pyx"
}
}OAuth2-Konfiguration
Ruft automatisch ein Zugriffstoken vor der Anfrage ab und injiziert es als Authorization-Header (überschreibt einen über headers gesetzten). Tokens werden im Speicher zwischengespeichert und vor Ablauf aktualisiert; bei einer 401-Antwort wird das zwischengespeicherte Token verworfen und die Anfrage einmal mit einem neuen Token wiederholt.
type OAuth2Config struct {
TokenUrl string `json:"token_url" yaml:"token_url"`
GrantType OAuth2GrantType `json:"grant_type" yaml:"grant_type"`
ClientId string `json:"client_id" yaml:"client_id"`
ClientSecret string `json:"client_secret" yaml:"client_secret"`
Scopes []string `json:"scopes" yaml:"scopes"`
RefreshToken string `json:"refresh_token" yaml:"refresh_token"`
EndpointParams map[string]string `json:"endpoint_params" yaml:"endpoint_params"`
AuthStyle string `json:"auth_style" yaml:"auth_style"`
TokenFile string `json:"token_file" yaml:"token_file"`
}TokenUrl – Endpunkt-URL für das Token. Unterstützt auch formatting
GrantType – enum["client_credentials", "refresh_token"], Standard ist "client_credentials". Verwenden Sie "refresh_token" für APIs, bei denen der Benutzer einmal zugestimmt hat (Google, Microsoft, ...) und Sie ein langlebiges Refresh-Token besitzen
ClientId/ClientSecret – Client-Anmeldedaten. Unterstützen auch formatting, z. B.
{{{FromEnv=CLIENT_SECRET}}}Scopes – angeforderte Scopes
RefreshToken – erforderlich für den Grant "refresh_token". Unterstützt auch formatting
EndpointParams – zusätzliche Parameter für den Token-Endpunkt (z. B.
audiencefür Auth0), nur für Grant "client_credentials"AuthStyle – enum["", "header", "params"] – wie Client-Anmeldedaten an den Token-Endpunkt übergeben werden: Basic-Auth-Header oder Anfrage-Body; leer bedeutet automatische Erkennung
TokenFile – optionaler Pfad (unterstützt
~/) zum Speichern von Tokens zwischen Läufen; das gespeicherte Token wird gegenüber RefreshToken bevorzugt und rotierte Refresh-Tokens werden zurückgeschrieben – erforderlich für Anbieter mit Einmal-Refresh-Tokens (GitHub Apps und ähnliche). Erstellen Sie es mit fitter_cli auth
Beispiel:
{
"method": "GET",
"oauth2": {
"token_url": "https://oauth2.googleapis.com/token",
"grant_type": "refresh_token",
"client_id": "{{{FromEnv=GOOGLE_CLIENT_ID}}}",
"client_secret": "{{{FromEnv=GOOGLE_CLIENT_SECRET}}}",
"refresh_token": "{{{FromEnv=GOOGLE_REFRESH_TOKEN}}}"
}
}Proxy-Konfiguration
type ProxyConfig struct {
// Proxy to be used for all requests. HTTP and SOCKS proxies are supported, for example
// `http://myproxy.com:3128` or `socks5://myproxy.com:3128`. Short form `myproxy.com:3128`
// is considered an HTTP proxy.
Server string `json:"server" yaml:"server"`
// Optional username to use if HTTP proxy requires authentication.
Username string `json:"username" yaml:"username"`
// Optional password to use if HTTP proxy requires authentication.
Password string `json:"password" yaml:"password"`
}Server – Adresse mit Schema des Proxy-Servers. Unterstützt auch formatting
Username – Benutzername für den Proxy (kann leer sein). Unterstützt auch formatting
Password – Passwort für den Proxy (kann leer sein). Unterstützt auch formatting
{
"server": "http://localhost:8080",
"username": "pyx"
}Umgebungsvariablen
FITTER_HTTP_WORKER – int[1000] – Standard-Anzahl gleichzeitiger HTTP-Worker
BrowserConnectorConfig
Connector-Typ, der das Abrufen von Daten über einen Browser emuliert
type BrowserConnectorConfig struct {
Chromium *ChromiumConfig `json:"chromium" yaml:"chromium"`
Docker *DockerConfig `json:"docker" yaml:"docker"`
Playwright *PlaywrightConfig `json:"playwright" yaml:"playwright"`
}Die Konfiguration kann eine der folgenden sein:
Chromium – lokal installiertes Chromium zum Abrufen von Daten verwenden
Docker – Docker als Dienst zum Starten eines Containers zum Abrufen von Daten verwenden
Playwright – Playwright-Framework zum Abrufen von Daten verwenden
Beispiel:
{
"docker": {
"wait": 10000,
"image": "docker.io/zenika/alpine-chrome:with-node",
"entry_point": "chromium-browser",
"purge": true
}
}Chromium
Verwendet lokal installiertes Chromium zum Abrufen der Daten
type ChromiumConfig struct {
Path string `yaml:"path" json:"path"`
Timeout uint32 `yaml:"timeout" json:"timeout"`
Wait uint32 `yaml:"wait" json:"wait"`
Flags []string `yaml:"flags" json:"flags"`
}Path – Pfad zur Chromium-Binärdatei
Timeout[sec] – Timeout für die Ausführung von Chromium
Wait[msec] – Timeout für das Laden der Seite
Flags – Flags für Chromium, Standard: "--headless", "--proxy-auto-detect", "--temp-profile", "--incognito", "--disable-logging", "--disable-extensions", "--no-sandbox"
Beispiel:
{
"path": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
"wait": 10000
}Docker
Verwendet Docker zum Starten eines Containers zum Abrufen von Daten
type DockerConfig struct {
Image string `yaml:"image" json:"image"`
EntryPoint string `json:"entry_point" yaml:"entry_point"`
Timeout uint32 `yaml:"timeout" json:"timeout"`
Wait uint32 `yaml:"wait" json:"wait"`
Flags []string `yaml:"flags" json:"flags"`
Purge bool `json:"purge" yaml:"purge"`
NoPull bool `yaml:"no_pull" json:"no_pull"`
PullTimeout uint32 `yaml:"pull_timeout" json:"pull_timeout"`
}Docker-Standardimage: docker.io/zenika/alpine-chrome
Image – Image für die Docker-Registry (mit Registry-Host angeben)
EntryPoint – Befehl, der im Container ausgeführt wird
Timeout[sec] – Timeout für das Ausführen des Containers (ohne Image-Pull)
Wait[msec] – Timeout für das Laden der Seite (funktioniert nur bei Chromium-basierten Containern)
Flags – Befehlsargumente zum Ausführen von Containern, Standard für Chromium-basiert: "--no-sandbox","--headless", "--proxy-auto-detect", "--temp-profile", "--incognito", "--disable-logging", "--disable-gpu"
Purge – soll der Container nach Abschluss der Arbeit entfernt werden (wie docker rm)
NoPull – verhindert das Pull des Images
PullTimeout – definiert das Timeout für den Image-Pull
Umgebungsvariablen
DOCKER_HOST – string – (EnvOverrideHost) zum Festlegen der URL zum Docker-Server.
DOCKER_API_VERSION – string – (EnvOverrideAPIVersion) zum Festlegen der zu verwendenden API-Version, für die neueste Version leer lassen.
DOCKER_CERT_PATH – string – (EnvOverrideCertPath) zum Festlegen des Verzeichnisses, aus dem die TLS-Zertifikate geladen werden (ca.pem, cert.pem, key.pem).
DOCKER_TLS_VERIFY – bool – (EnvTLSVerify) zum Aktivieren oder Deaktivieren der TLS-Verifizierung (standardmäßig deaktiviert)
Beispiel:
{
"wait": 10000,
"image": "docker.io/zenika/alpine-chrome:with-node",
"entry_point": "chromium-browser",
"purge": true
}Playwright
Browser über das Playwright-Framework ausführen
type PlaywrightConfig struct {
Browser PlaywrightBrowser `json:"browser" yaml:"browser"`
Install bool `yaml:"install" json:"install"`
Timeout uint32 `yaml:"timeout" json:"timeout"`
Wait uint32 `yaml:"wait" json:"wait"`
TypeOfWait *playwright.WaitUntilState `json:"type_of_wait" yaml:"type_of_wait"`
PreRunScript string `json:"pre_run_script" yaml:"pre_run_script"`
PostRunScript string `json:"post_run_script" yaml:"post_run_script"`
Stealth bool `json:"stealth" yaml:"stealth"`
StorageStateFile string `json:"storage_state_file" yaml:"storage_state_file"`
IndexedDB bool `json:"indexed_db" yaml:"indexed_db"`
Proxy *ProxyConfig `yaml:"proxy" json:"proxy"`
}Browser – enum["Chromium", "FireFox", "WebKit"] – welcher Browser verwendet werden soll
Install – soll der Browser installiert werden (lädt beim ersten Gebrauch den Treiber + Browser passend zur eingebauten
playwright-go-Version herunter; nicht erforderlich mit demghcr.io/pxyup/fitter-mcp:playwright-Image, das sie vorinstalliert enthält)Timeout[sec] – Timeout für die Ausführung von Playwright
Wait[sec] – Timeout für das Laden der Seite
TypeOfWait – enum["load", "domcontentloaded", "networkidle", "commit"] – auf welchen Zustand der Seite gewartet wird, Standard ist "load"
PreRunScript[""] – Skript, das über AddInitScript injiziert und vor der Ausführung von Seitenskripten ausgeführt wird (bei Dokumenterstellung, vor Abschluss der Navigation). Nützlich zum Patchen der Umgebung (navigator-Überschreibungen, API-Stubs). Kann nicht auf das geladene DOM zugreifen. Unterstützt auch Platzhalter {PL}
PostRunScript[""] – Skript, das nach dem Laden der Seite, vor dem Lesen des Seiteninhalts, ausgeführt wird. Nützlich für DOM-Interaktionen (Klicks, Scrollen). Unterstützt auch Platzhalter {PL}
Stealth[false] – Skript hinzufügen, um Bot-Abwehr zu umgehen
StorageStateFile[""] – Pfad (unterstützt
~/) zu einer Playwright-Storage-State-JSON (Cookies + localStorage): wird vor der Navigation in den Browser-Kontext geladen und nach jedem Lauf zurückgeschrieben, sodass aktualisierte Sitzungen erhalten bleiben. Ermöglicht Headless-Läufen die Wiederverwendung eines echten Logins – erstellen Sie die Datei einmal mit fitter_cli browser-login. Verwenden Sie denselbenbrowserfür Login und Scraping: Websites können Sitzungen an den Browser-Fingerprint binden. Unterstützt auch formattingIndexedDB[false] – IndexedDB in den gespeicherten Storage-State einbeziehen (einige SPAs, z. B. Firebase Auth, speichern Tokens dort)
Proxy – Proxy für die Anfrage einrichten config
Beispiel
{
"timeout": 30,
"wait": 30,
"install": false,
"browser": "Chromium"
}Related MCP server: MCP Server Fetch Python
Model
Mit Model definieren wir das Ergebnis des Scrapings
type Model struct {
ObjectConfig *ObjectConfig `yaml:"object_config" json:"object_config"`
ArrayConfig *ArrayConfig `json:"array_config" yaml:"array_config"`
BaseField *BaseField `json:"base_field" yaml:"base_field"`
IsArray bool `json:"is_array" yaml:"is_array"`
}Die Konfiguration kann eine der folgenden sein:
ObjectConfig – Konfiguration des Objektformats
ArrayConfig – Konfiguration des Array-Formats
BaseField – Konfiguration eines einzelnen/generierten Felds
IsArray – bool[false] – erzwingt die Angabe, dass das Feld ein Array ist (verwendbar im Fall von model field mit base field)
Beispiel:
{
"object_config": {}
}ObjectConfig
Konfiguration des Objekts und der Felder
type ObjectConfig struct {
Fields map[string]*Field `json:"fields" yaml:"fields"`
Field *BaseField `json:"field" yaml:"field"`
ArrayConfig *ArrayConfig `json:"array_config" yaml:"array_config"`
Condition string `json:"condition" yaml:"condition"`
}Condition – optionaler condition-Ausdruck, der vor der Auflösung gegen den Quellknoten ausgewertet wird; wenn false, wird das gesamte Objekt vom übergeordneten Element weggelassen (Felder werden überhaupt nicht aufgelöst)
Die Konfiguration kann eine der folgenden sein:
Fields – Map der Felddefinitionen; Schlüssel – Feldname, Wert – Konfiguration
Field – für Elemente eines Arrays verwendet; Felder, die wie Basistypen wie "string", "int" usw. deserialisiert werden (hier für den Fall von Arrays mit Basistypen verwendet)
ArrayConfig – für Elemente eines Arrays verwendet; Deserialisierung von Array von Arrays
Beispiel:
{
"fields": {
"title": {
"base_field": {
"type": "string",
"path": "type"
}
}
}
}ArrayConfig
Konfiguration des Arrays und der Felder
type ArrayConfig struct {
RootPath string `json:"root_path" yaml:"root_path"`
Reverse bool `yaml:"reverse" json:"reverse"`
ItemConfig *ObjectConfig `json:"item_config" yaml:"item_config"`
LengthLimit uint32 `json:"length_limit" yaml:"length_limit"`
Condition string `json:"condition" yaml:"condition"`
ItemCondition string `json:"item_condition" yaml:"item_condition"`
StaticConfig *StaticArrayConfig `json:"static_array" yaml:"static_array"`
}RootPath – Selektor zum Finden des Wurzelelements des Arrays oder des wiederholten Elements bei HTML-Parsing; die Größe des Arrays entspricht der Anzahl der untergeordneten Elemente unter der Wurzel
Reverse – bool[false] – gibt an, dass die Iteration in umgekehrter Reihenfolge verwendet werden soll (n bis 1)
LengthLimit – feste Größe des Arrays (nur für generierte Arrays; nicht für statische). Hinweis: Wenn die Quelle weniger Elemente als das Limit enthält, wird das Array mit nachgestellten
nulls aufgefüllt, um die deklarierte Größe beizubehalten (dies ist beabsichtigt) – lassen Sielength_limitweg, um stattdessen exakt die Quelllänge zu erhaltenCondition – optionaler condition-Ausdruck, der vor der Auflösung gegen den Quellknoten ausgewertet wird; wenn false, wird das gesamte Array vom übergeordneten Element weggelassen
ItemCondition – optionaler condition-Ausdruck, der gegen jedes erstellte Element ausgewertet wird (fRes – Elementwert, fSrc – Quellelement, fIndex – Elementindex); Elemente, die false ergeben, werden aus dem Array entfernt – deklarative Filterung. Wird nicht auf static_array angewendet
Die Konfiguration kann eine der folgenden sein:
ItemConfig – Konfiguration jedes Elements des Arrays
StaticConfig – Konfiguration des statischen Arrays
Beispiel:
{
"root_path": "#content dt.quote > a",
"item_config": {
"field": {
"type": "string"
}
}
}Feld
Gemeinsame Eigenschaften des Felds
type Field struct {
BaseField *BaseField `json:"base_field" yaml:"base_field"`
ObjectConfig *ObjectConfig `json:"object_config" yaml:"object_config"`
ArrayConfig *ArrayConfig `json:"array_config" yaml:"array_config"`
FirstOf []*Field `json:"first_of" yaml:"first_of"`
}Config kann eines der folgenden sein:
BaseField – Felder, die wie Basistypen wie „string", „int" usw. deserialisiert werden
ObjectConfig – falls unser Feld ein verschachteltes Objekt ist
ArrayConfig – falls unser Feld ein Array ist
FirstOf – das erste nicht leere aufgelöste Feld wird ausgewählt
Beispiel:
{
"base_field": {
"type": "string",
"path": "div.current-temp span.heading"
}
}BaseField
Falls wir statische Informationen erhalten oder neue generieren möchten
type BaseField struct {
Type FieldType `yaml:"type" json:"type"`
Path string `yaml:"path" json:"path"`
HTMLAttribute string `json:"html_attribute" yaml:"html_attribute"`
Condition string `json:"condition" yaml:"condition"`
Generated *GeneratedFieldConfig `yaml:"generated" json:"generated"`
FirstOf []*BaseField `json:"first_of" yaml:"first_of"`
}FieldType – enum["null", "boolean", "string", "int", "int64", "float", "float64", "array", "object", "html", "raw_string"] – statisches Feld zum Parsen. Wichtig: Der Typ html funktioniert nur mit einem Connector, der HTML zurückgibt (HTMLAttribute hat in diesem Fall keine Wirkung). Beispiel
Path – Selektor (relativ, falls es ein Array-Kind ist) zum Parsen
HTMLAttribute – zusätzlicher Wert, der nur beim HTML-Parsing über goquery wirkt. Hier kannst du angeben, welches Attribut geparst werden soll.
Condition – optionale Bedingung, die gegen den extrahierten Wert ausgewertet wird (fRes/fResJson/fResRaw, fIndex; fSrc – der Knoten, aus dem das Feld aufgelöst wurde, einschließlich Geschwister); wenn false, wird das Feld aus dem übergeordneten Objekt/Array weggelassen, statt null zu erzeugen. Wird vor Generated ausgewertet, sodass eine false-Bedingung auch generierte Arbeit überspringt (Unteranfragen, Dateidownloads)
Wichtig: Standardmäßig wird der Typ „string" getrimmt und alle Sonderzeichen werden ersetzt. Wenn du einen einfachen String benötigst, verwende „raw_string".
Config kann eines der folgenden sein oder leer:
Generated – Feld kann generiert werden, mit benutzerdefinierter Konfiguration
FirstOf – das erste nicht leere aufgelöste Feld wird ausgewählt
Beispiele
{
"generated": {
"uuid": {}
}
}{
"type": "string",
"path": "text()"
}Bedingte Felder
Jedes Feld kann eine condition tragen – einen expr-lang-Ausdruck (vordefinierte Werte). Wenn er zu etwas anderem als true ausgewertet wird, wird das Feld aus der Ausgabe weggelassen (der Schlüssel/das Element verschwindet), nicht auf null gesetzt. Ein ungültiger Ausdruck lässt das Feld ebenfalls weg und protokolliert einen Fehler.
Wo die Bedingung ausgewertet wird:
BaseField.
condition– nach der Extraktion:fResist der extrahierte Wert,fSrcder Knoten, aus dem das Feld aufgelöst wurde (einschließlich seiner Geschwister) – so kannfSrc.on_sale == trueein Feld an Daten koppeln, die du nicht extrahiert hast. Eine false-Bedingung überspringt die generierte Arbeit vollständig (keine Unteranfrage, kein Dateidownload)ObjectConfig.
condition/ ArrayConfig.condition– vor der Auflösung:fRes/fSrcsind der Quellknoten (geparster Wert für JSON, Textinhalt für HTML)ArrayConfig.
item_condition– gegen jedes erstellte Element:fResist das Element,fSrcdas Quell-Element, aus dem es erstellt wurde,fIndexsein Index; false-Elemente werden verworfen – deklarative Array-Filterung. VerwendefSrc, um nach Quellattributen zu filtern, ohne sie in die Ausgabe aufzunehmen
Array-Elemente filtern – fSrc.in_stock liest das Quell-Element (nicht in die Ausgabe extrahiert), fRes.price das erstellte Element:
{
"array_config": {
"root_path": "products",
"item_condition": "fSrc.in_stock && fRes.price > 0",
"item_config": {
"fields": {
"title": { "base_field": { "type": "string", "path": "title" } },
"price": { "base_field": { "type": "float", "path": "price" } }
}
}
}
}Einen Schlüssel weglassen, es sei denn, der Wert besteht eine Prüfung:
{
"discount": {
"base_field": {
"type": "float",
"path": "discount_pct",
"condition": "fRes > 0"
}
}
}Sonderfälle:
in einem statischen Array bleibt ein weggelassenes Element
null(Positionen sind per Definition fest, Indizes verschieben sich nie)wenn die Root-Modell-Config weggelassen wird, ist das Parse-Ergebnis
nullinnerhalb von first_of zählt ein Zweig mit false-Bedingung als leer, sodass der nächste Zweig versucht wird
Ausführbares Beispiel: examples/config_conditions.json
GeneratedFieldConfig
Bietet die Funktionalität, Felder im laufenden Betrieb zu generieren
type GeneratedFieldConfig struct {
UUID *UUIDGeneratedFieldConfig `yaml:"uuid" json:"uuid"`
Static *StaticGeneratedFieldConfig `yaml:"static" json:"static"`
Formatted *FormattedFieldConfig `json:"formatted" yaml:"formatted"`
Plugin *PluginFieldConfig `yaml:"plugin" json:"plugin"`
Calculated *CalculatedConfig `yaml:"calculated" json:"calculated"`
File *FileFieldConfig `yaml:"file" json:"file"`
Model *ModelField `yaml:"model" json:"model"`
FileStorageField *FileStorageField `json:"file_storage" yaml:"file_storage"`
}Config kann eines der folgenden sein:
UUID – zufällige UUID V4 generieren
Static – statisches Feld generieren
Formatted – Feld formatieren
Model – Modell, das aus einem anderen Connector und Modell generiert wird
Plugin – Plugin-Feld
Calculated – berechnetes Feld
File – Dateifeld (zum Herunterladen einer Datei vom Server)
FileStorage – Dateifeld, das in einer lokalen Datei gespeichert werden kann
Beispiele:
{
"uuid": {}
}https://github.com/PxyUp/fitter/blob/master/examples/cli/config_cli.json#L58
{
"model": {
"type": "array",
"model": {
"array_config": {
"root_path": "#content dt.quote > a",
"item_config": {
"field": {
"type": "string"
}
}
}
},
"connector_config": {
"response_type": "HTML",
"url": "http://www.quotationspage.com/random.php",
"attempts": 3,
"browser_config": {
"chromium": {
"path": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
"wait": 10000
}
}
}
}
}UUID
Generiert im laufenden Betrieb eine zufällige UUID V4, kann zur Erzeugung einer eindeutigen ID verwendet werden
type UUIDGeneratedFieldConfig struct {
Regexp string `yaml:"regexp" json:"regexp"`
}Regexp – stellt einen Matcher bereit, der verwendet werden kann, um einen Teil der generierten UUID zu erhalten
Static
Generiert ein statisches Feld
type StaticGeneratedFieldConfig struct {
Type FieldType `yaml:"type" json:"type"`
Value string `json:"value" yaml:"value"`
Raw json.RawMessage `json:"raw" yaml:"raw"`
}Type – enum["null", "boolean", "string", "int","int64","float","float64", "array", "object"] – Typ des Felds
Value – String-Wert des Felds
Raw – reiner JSON-Wert des Felds
Beispiel
{
"type": "int",
"value": "65"
}{
"type": "array",
"value": "[65,45]"
}{
"type": "array",
"raw": [65,45]
}Formatierte Feld-Config
Generiert ein formatiertes Feld, das den Wert vom übergeordneten Basisfeld übernimmt
type FormattedFieldConfig struct {
Template string `yaml:"template" json:"template"`
}Template – Vorlage mit Platzhalter {PL}, in die der übergeordnete Wert als String eingefügt wird
Beispiel: https://github.com/PxyUp/fitter/blob/master/examples/cli/config_cli.json#L98
{
"template": "https://news.ycombinator.com/item?id={PL}"
}Dateispeicher-Feld
Feld kann verwendet werden, um das Feldergebnis als lokale Datei zu speichern
type FileStorageField struct {
Content string `json:"content" yaml:"content"`
Raw json.RawMessage `yaml:"raw" yaml:"raw"`
FileName string `json:"file_name" yaml:"file_name"`
Path string `json:"path" yaml:"path"`
Append bool `json:"append" yaml:"append"`
}Content – Vorlagen-String für den Inhalt. Wichtig: kann mit Einfügung des übergeordneten Werts als String verwendet werden
Raw – roher JSON-Inhalt des Felds. Wichtig: kann mit Einfügung des übergeordneten Werts als String verwendet werden
FileName – lokaler Dateiname zum Speichern der Datei. Standardmäßig wird versucht, den Dateinamen aus dem Header zu erhalten, danach aus der URL. Wichtig: kann mit Einfügung des übergeordneten Werts als String verwendet werden.
Path – lokales übergeordnetes Verzeichnis zum Speichern der Datei. Standardpfad ist das Prozessverzeichnis. Wichtig: kann mit Einfügung des übergeordneten Werts als String verwendet werden
Append[false] – an Datei anhängen oder nicht
{
"content": "{{{id}}}, {{{message}}}\n",
"append": true,
"file_name": "{{{id}}}.csv",
"path": "/Users/pxyup/fitter/examples/cli/test/csv"
}Dateifeld
Feld kann verwendet werden, um eine Datei lokal vom Server herunterzuladen
type FileFieldConfig struct {
Config *ServerConnectorConfig `yaml:"config" json:"config"`
Url string `yaml:"url" json:"url"`
FileName string `json:"file_name" yaml:"file_name"`
Path string `json:"path" yaml:"path"`
}Config – ServerConfig, verwendet den Standard-fitter-http.Client zum Senden der Anfrage
Url – URL des Bildes. Wichtig: URL im Connector kann mit Einfügung des übergeordneten Werts als String verwendet werden
FileName – lokaler Dateiname zum Speichern der Datei. Standardmäßig wird versucht, den Dateinamen aus dem Header zu erhalten, danach aus der URL. Wichtig: kann mit Einfügung des übergeordneten Werts als String verwendet werden.
Path – lokales übergeordnetes Verzeichnis zum Speichern der Datei. Standardpfad ist das Prozessverzeichnis. Wichtig: kann mit Einfügung des übergeordneten Werts als String verwendet werden
Das Ergebnis des Felds ist der lokale Dateipfad als String
{
"url": "https://images.shcdn.de/resized/w680/p/dekostoff-gobelinstoff-panel-oriental-cat-46-x-46_P19-KP_2.jpg",
"path": "/Users/pxyup/fitter/bin",
"config": {
"method": "GET"
}
}Mit weitergegebener URL (Einfügung des übergeordneten Werts als String)
{
"url": "https://picsum.photos{PL}",
"path": "/Users/pxyup/fitter/bin",
"config": {
"method": "GET"
}
}Config-Beispiel:
https://github.com/PxyUp/fitter/blob/master/examples/cli/config_image.json
https://github.com/PxyUp/fitter/blob/master/examples/cli/config_image_multiple.json
Berechnetes Feld
Feld kann je nach Ausdruck verschiedene Typen generieren
type CalculatedConfig struct {
Type FieldType `yaml:"type" json:"type"`
Expression string `yaml:"expression" json:"expression"`
}Type – resultierender Typ des Ausdrucks
Expression – Ausdruck zur Berechnung (wir verwenden diese Bibliothek für berechnete Ausdrücke)
Vordefinierte Werte
FNull – Alias für builder.Nullvalue
FNil – Alias für nil
isNull(value T) – Funktion zum Prüfen, ob der Wert FNull ist
fRes – rohes (mit korrektem Typ) Ergebnis aus dem Parsen des Basisfelds
fIndex – Index im übergeordneten Array (nur wenn das übergeordnete Element ein Array-Feld war)
fResJson – JSON-String-Darstellung des rohen Ergebnisses
fResRaw – Ergebnis im Byte-Format
fSrc – nur in condition/item_condition-Ausdrücken: der Quellknoten, aus dem der Wert aufgelöst wurde (geparster Wert für JSON – einschließlich Geschwister, Textinhalt für HTML). Nicht verfügbar in berechneten/formatierten/Notifier-Ausdrücken
FNewLine – Zeilenumbruch-Trennzeichen
{
"type": "bool",
"expression": "fRes > 500"
}Plugin-Feld
Feld kann ein externes Plugin für fitter sein
type PluginFieldConfig struct {
Name string `json:"name" yaml:"name"`
Config json.RawMessage `json:"config" yaml:"config"`
}Name – Name des Plugins (ohne Erweiterung, nur Name)
Config – JSON-Config des Plugins
Modell-Feld
Feldtyp, der im laufenden Betrieb durch ein neues Modell und Connector generiert werden kann
type ModelField struct {
// Type of parsing
ConnectorConfig *ConnectorConfig `yaml:"connector_config" json:"connector_config"`
// Model of the response
Model *Model `yaml:"model" json:"model"`
Type FieldType `yaml:"type" json:"type"`
Path string `yaml:"path" json:"path"`
Expression string `yaml:"expression" json:"expression"`
}ConnectorConfig – welcher Connector verwendet werden soll. Wichtig: URL im Connector kann mit Einfügung des übergeordneten Werts als String verwendet werden
Model – Konfiguration des zugrunde liegenden Modells
Type – enum["null", "boolean", "string", "int", "int64", "float", "float64", "array", "object"] – Typ des generierten Felds
Path – falls wir keine Informationen aus dem generierten Feld extrahieren können, können wir einen JSON-Selektor zur Extraktion verwenden
Expression – String, der zur Nachbearbeitung des Modells verwendet werden kann (ignoriert das Path-Feld)
Beispiele:
https://github.com/PxyUp/fitter/blob/master/examples/cli/config_cli.json#L60
{
"type": "array",
"model": {
"array_config": {
"root_path": "#content dt.quote > a",
"item_config": {
"field": {
"type": "string"
}
}
}
}
}https://github.com/PxyUp/fitter/blob/master/examples/cli/config_weather.json#L37
{
"type": "string",
"path": "temp.temp",
"model": {
"object_config": {
"fields": {
"temp": {
"base_field": {
"type": "string",
"path": "//div[@id='forecast_list_ul']//td/b/a/@href",
"generated": {
"model": {
"type": "string",
"model": {
"object_config": {
"fields": {
"temp": {
"base_field": {
"type": "string",
"path": "div.current-temp span.heading"
}
}
}
}
},
"connector_config": {
"response_type": "HTML",
"attempts": 4,
"url": "https://openweathermap.org{PL}",
"browser_config": {
"playwright": {
"timeout": 30,
"wait": 30,
"install": false,
"browser": "FireFox",
"type_of_wait": "networkidle"
}
}
}
}
}
}
}
}
}
},
"connector_config": {
"response_type": "xpath",
"attempts": 3,
"url": "https://openweathermap.org/find?q={PL}",
"browser_config": {
"playwright": {
"timeout": 30,
"wait": 30,
"install": false,
"browser": "Chromium"
}
}
}
}Static-Array-Config
Bietet die Generierung eines statischen (festen Länge) Arrays
type StaticArrayConfig struct {
Items map[uint32]*Field `yaml:"items" json:"items"`
Length uint32 `yaml:"length" json:"length"`
}Items – map[uint32]*Field – Schlüssel ist der Index im Array, Wert ist die Felddefinition
Length – wenn gesetzt (1+), kann zur Definition einer benutzerdefinierten Array-Länge verwendet werden
Beispiele:
{
"0": {
"base_field": {
"type": "string",
"path": "div.current-temp span.heading"
}
}
}{
"length": 4,
"0": {
"base_field": {
"type": "string",
"path": "div.current-temp span.heading"
}
}
}{
"length": 4,
"2": {
"base_field": {
"type": "string",
"path": "div.current-temp span.heading"
}
}
}Platzhalterliste
{PL} – zum Einfügen eines Werts
{INDEX} – zum Einfügen des Index im übergeordneten Array
{HUMAN_INDEX} – zum Einfügen des Index im übergeordneten Array auf menschliche Weise
{{{json_path}}} – erhält Informationen aus dem weitergegebenen „object"/„array"-Feld
{{{RefName=SomeName}}} – Referenz-Wert nach Name abrufen. Beispiel
{{{RefName=SomeName json.path}}} – Referenz-Wert nach Name abrufen und Wert per JSON-Pfad extrahieren. Beispiel
{{{FromEnv=ENV_KEY}}} – Wert aus einer Umgebungsvariable abrufen
{{{FromExp=fRes + 5 + fIndex}}} – Wert aus dem Ausdruck abrufen. Vordefinierte Werte
{{{FromInput=.}}} oder {{{FromInput=json.path}}} – Wert aus der Eingabe des Triggers oder der Bibliothek abrufen
{{{FromFile=./test_file.log}}} – Wert aus einer Datei per Pfad abrufen. Der Dateiinhalt kann ebenfalls Platzhalter enthalten
{{{FromURL=http://localhost:8081}}} – Antwort von einer URL abrufen
Beispiele:
{{{FromExp="{{{FromEnv=TEST_VAL}}}" + "hello"}}}Current time is: {PL} with token from TokenRef={{{RefName=TokenRef}}} and TokenObjectRef={{{RefName=TokenObjectRef token}}}Current time is: {PL} with token from TokenRef={{{RefName=TokenRef}}} and TokenObjectRef={{{RefName=TokenObjectRef token}}}TokenRef={{{RefName=TokenRef}}} and TokenObjectRef={{{RefName=TokenObjectRef token}}} Object={{{value}}} {PL} Env={{{FromEnv=TEST_VAL}}} {INDEX} {HUMAN_INDEX}Referenzen
Spezielle Map, die vorab abgerufen (vor jeder Verarbeitung) wird und für Connector oder Platzhalter verwendet werden kann
Kann verwendet werden für:
JWT-Token cachen und in Headern verwenden
Werte cachen
usw.
Referenz
type Reference struct {
*ModelField
Expire *uint32 `yaml:"expire" json:"expire"`
}ModelField – ist eine eingebettete Struktur, du kannst dieselben Felder verwenden
Expire[sec] – Dauer, nach der die Referenz nach dem Abrufen abläuft. Nicht gesetzt => für immer gecacht. Auf 0 gesetzt => jedes Mal neu abrufen. Auf n > 0 gesetzt => für n Sekunden gecacht
Für Fitter
type RefMap map[string]*Reference
type Config struct {
// Other Config Fields
Limits *Limits `yaml:"limits" json:"limits"`
References RefMap `json:"references" yaml:"references"`
}Für Fitter Cli
type RefMap map[string]*Reference
type CliItem struct {
// Other Config Fields
Limits *Limits `yaml:"limits" json:"limits"`
References RefMap `json:"references" yaml:"references"`
}References – map[string]*Reference – Objekt, in dem der Schlüssel der Referenzname ist (kann für Connector oder Platzhalter verwendet werden) und der Wert eine Referenz ist
Beispiel
https://github.com/PxyUp/fitter/blob/master/examples/cli/config_ref.json#L2
{
"references": {
"TokenRef": {
"expire": 10,
"connector_config": {
"response_type": "json",
"static_config": {
"value": "\"plain token\""
}
},
"model": {
"base_field": {
"type": "string"
}
}
},
"TokenObjectRef": {
"connector_config": {
"response_type": "json",
"static_config": {
"value": "{\"token\":\"token from object\"}"
}
},
"model": {
"object_config": {
"fields": {
"token": {
"base_field": {
"type": "string",
"path": "token"
}
}
}
}
}
}
}
}Notifier
Optionale Pro-Element-Config item.notifier_config, die das Parse-Ergebnis nach der Verarbeitung irgendwohin überträgt. Das Ergebnis wird weiterhin wie gewohnt zurückgegeben (CLI/MCP-Ausgabe, Dienstprotokolle); der Notifier liefert es zusätzlich. Funktioniert in Fitter (Dienstmodus), Fitter_CLI und Fitter_MCP.
type NotifierConfig struct {
Expression string `yaml:"expression" json:"expression"`
Force bool `json:"force" yaml:"force"`
SendArrayByItem bool `yaml:"send_array_by_item" json:"send_array_by_item"`
Template string `yaml:"template" json:"template"`
// exactly ONE destination:
Console *ConsoleConfig `yaml:"console" json:"console"`
TelegramBot *TelegramBotConfig `yaml:"telegram_bot" json:"telegram_bot"`
Http *HttpConfig `yaml:"http" json:"http"`
Redis *RedisNotifierConfig `json:"redis" yaml:"redis"`
File *FileStorageField `json:"file" yaml:"file"`
}Expression - optionale expr-lang-Bedingung: nur benachrichtigen, wenn sie wahr ist. Das Parsing-Ergebnis ist verfügbar als
fRes(geparster Wert),fResRaw(Rohbytes),fResJson(JSON-String), z. B.len(fResRaw) > 0Force - auch benachrichtigen, wenn das Parsing mit einem Fehler abgeschlossen wurde
SendArrayByItem - wenn das Ergebnis ein Array ist, jedes Element als separate Benachrichtigung senden
Template - optionale Vorlage, die auf das Ergebnis angewendet wird, bevor es gesendet wird, Platzhalter erlaubt
Destination - genau eines von
console,telegram_bot,http,redis,file
Destination-Konfigurationen:
type HttpConfig struct {
Url string `yaml:"url" json:"url"`
Method string `json:"method" yaml:"method"`
Headers map[string]string `yaml:"headers" json:"headers"`
Timeout uint32 `yaml:"timeout" json:"timeout"`
}
type TelegramBotConfig struct {
Token string `json:"token" yaml:"token"`
UsersId []int64 `json:"users_id" yaml:"users_id"`
Pretty bool `json:"pretty" yaml:"pretty"`
OnlyMsg bool `json:"only_msg" yaml:"only_msg"`
}
type RedisNotifierConfig struct {
Addr string `json:"addr" yaml:"addr"`
Password string `json:"password" yaml:"password"`
DB int `json:"db" yaml:"db"`
Channel string `json:"channel" yaml:"channel"`
}
type ConsoleConfig struct {
OnlyResult bool `json:"only_result" yaml:"only_result"`
}Das file-Destination verwendet dasselbe FileStorageField wie der Dateifeldtyp.
Beispiel (examples/config_telegram.json):
{
"item": {
"connector_config": { "...": "..." },
"model": { "...": "..." },
"notifier_config": {
"expression": "len(fResRaw) > 0",
"telegram_bot": {
"token": "{{{FromEnv=TG_TOKEN}}}",
"users_id": [123456],
"pretty": true
}
}
}
}Grenzen
Stellt Begrenzungen bereit, um DDOS und hohe Speichernutzung zu verhindern.
type Limits struct {
HostRequestLimiter HostRequestLimiter `yaml:"host_request_limiter" json:"host_request_limiter"`
ChromiumInstance uint32 `yaml:"chromium_instance" json:"chromium_instance"`
DockerContainers uint32 `yaml:"docker_containers" json:"docker_containers"`
PlaywrightInstance uint32 `yaml:"playwright_instance" json:"playwright_instance"`
}HostRequestLimiter - map[string]int64 - Begrenzung pro Hostname, Schlüssel ist der Host, Wert ist die Anzahl paralleler Anfragen (Verwendung für Server-Connector)
ChromiumInstance - Anzahl paralleler chromium-Instanzen
DockerContainers - Anzahl paralleler docker-Instanzen
PlaywrightInstance - Anzahl paralleler playwright-Instanzen
https://github.com/PxyUp/fitter/blob/master/examples/cli/config_cli.json#L2
{
"limits": {
"host_request_limiter": {
"hacker-news.firebaseio.com": 5
},
"chromium_instance": 3,
"docker_containers": 3,
"playwright_instance": 3
}
}Available Tools
6 toolsfitter_config_referenceA
Return a condensed reference of the Fitter config format (connectors, parsers, model/field schema, placeholders, notifiers, references, limits) with working examples. Use it before authoring a config for fitter_run.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description carries burden. Describes output but does not explicitly state that tool is read-only or has no side effects, though context implies safe operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with purpose, no fluff. Every part earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no parameters or output schema, description sufficiently covers purpose and usage. Could mention response format but not critical for a reference tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
No parameters, schema coverage is 100% trivially. Baseline 4 applies, and description adds value by listing what the reference includes.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it returns a condensed reference of the Fitter config format with working examples, and distinguishes itself from sibling run tools by advising use before authoring a config for fitter_run.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly recommends using before authoring a config for fitter_run, providing clear context. However, it does not mention exclusions or alternatives, but siblings are run tools making differentiation obvious.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fitter_inspect_urlA
Fetch a URL and return a compact structure outline plus candidate selectors/paths, so you can author a fitter config that matches on the first try instead of guessing selectors and getting nulls. For JSON it lists gjson paths with types and sample values; for HTML it lists repeated elements (candidate array_config root_path / list rows) and link/heading selectors. For client-rendered SPAs (content built by JavaScript), a plain fetch sees only an empty shell — the output warns when it detects one; pass render:true to render it in a headless browser first (mirrors what a browser_config scrape would see). Read-only helper that does NOT extract data — use it before fitter_run, then fitter_run to actually extract.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | HTTP(S) URL to fetch and inspect for its structure and candidate selectors. | |
| render | No | Render the page in a headless browser (Playwright/Chromium) before inspecting — needed for client-rendered SPAs whose content is built by JavaScript and is absent from the raw HTML. Requires browser support (the fitter-mcp:playwright image or a local Playwright install). | |
| response_type | No | Optional hint for how to read the response: json, HTML, xpath or XML. Empty auto-detects from the Content-Type/body. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It clearly states the tool is read-only and does not extract data, and explains behavior for different content types (JSON, HTML, SPAs) and the render option.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is detailed but each sentence adds unique value, covering purpose, output, parameter usage, and distinctions from execution tools. It is front-loaded with the primary purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite no output schema, the description describes the output as a 'compact structure outline plus candidate selectors/paths' and gives specifics for JSON and HTML. It also covers the render behavior for SPAs, making the tool's behavior well understood.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description expands on each parameter beyond the schema: url as the target, render for SPAs, and response_type as an optional hint with auto-detection. It explains why the parameters matter and how they affect the output.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Fetch a URL and return a compact structure outline') and differentiates from sibling tools by positioning it as an inspection step before fitter_run. Clearly identifies the tool's role.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use it ('before fitter_run') and what it does not do ('does NOT extract data'), plus provides guidance on when to set render:true for SPAs. Also mentions the response_type hint.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fitter_runA
Run a Fitter scraping/parsing config passed inline (JSON or YAML) and return the extracted data as JSON. Fitter fetches data via a connector (HTTP request, headless browser, static value, file, ...) and extracts structured data using json/HTML/XML/xpath selectors described by a declarative model. Call fitter_config_reference first if you are unsure about the config format.
| Name | Required | Description | Default |
|---|---|---|---|
| input | No | Optional input value (plain string or JSON), available in the config via {{{FromInput=.}}} or {{{FromInput=json.path}}} placeholders. | |
| config | Yes | Fitter CliItem config as a JSON or YAML string. Top-level keys: item (required), limits, references. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must disclose behaviors. It mentions fetching data via connectors and extracting data, implying network access. However, it omits potential side effects like rate limits, authentication needs, or error scenarios, which would strengthen transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is brief, with a clear structure: first sentence states the tool's purpose, second explains the underlying Fitter mechanism, third gives a usage tip. Every sentence contributes directly to understanding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with two parameters, no output schema, and no annotations, the description provides sufficient context: config format, supported selectors, and a reference to the config spec tool. It could be more complete by noting potential timeouts or result size limitations, but overall it covers the essential information.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% (both parameters described). The description adds context beyond the schema by explaining that config is JSON/YAML, highlighting top-level keys (item, limits, references), and stating that output is JSON. This adds meaningful value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the action ('Run a Fitter scraping/parsing config passed inline') and the resource (inline config). It distinguishes from siblings by specifying 'inline', contrasting with file- and URL-based tools. The purpose is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description advises calling fitter_config_reference first if unsure about the config format, providing clear guidance. However, it does not explicitly compare this tool to fitter_run_file or fitter_run_url, leaving the selection of the appropriate sibling somewhat implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fitter_run_fileA
Run a Fitter scraping/parsing config from a local JSON or YAML file and return the extracted data as JSON. Same as fitter_run but reads the config from disk.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Absolute path to a Fitter config file (.json, .yaml or .yml) with top-level keys: item (required), limits, references. | |
| input | No | Optional input value (plain string or JSON), available in the config via {{{FromInput=.}}} or {{{FromInput=json.path}}} placeholders. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description must fully disclose behavioral traits. It states the tool returns extracted data as JSON but does not mention whether modifications occur, required permissions, or error handling (e.g., file not found). The description is minimal and lacks transparency beyond the basic operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise with two sentences, front-loading the primary purpose. Every sentence adds value: first defines the tool, second clarifies the difference from a sibling. No fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has 2 parameters and no output schema, the description covers the basic purpose but omits important context like what happens if the file is invalid, permissions needed, or error scenarios. It is adequate for simple use but has gaps compared to a fully transparent description.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds minimal additional meaning beyond the schema; it only reiterates that 'input' is optional and used with placeholders, which the schema already covers. No further value is added for the 'path' parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description clearly states the verb (Run), the resource (Fitter config file), and distinguishes it from fitter_run by specifying 'reads the config from disk.' It also indicates the output format (JSON). This differentiates it from sibling tools like fitter_config_reference, fitter_run, and fitter_run_url.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly notes 'Same as fitter_run but reads the config from disk,' which helps users decide between this tool and fitter_run. However, it does not provide explicit when-not-to-use scenarios or mention other alternatives besides the direct sibling comparison.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fitter_run_urlA
Run a Fitter scraping/parsing config downloaded from an HTTP(S) URL (JSON or YAML) and return the extracted data as JSON. Same as fitter_run but fetches the config from a remote location, e.g. a raw GitHub link.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | HTTP(S) URL of a Fitter config (JSON or YAML) with top-level keys: item (required), limits, references. | |
| input | No | Optional input value (plain string or JSON), available in the config via {{{FromInput=.}}} or {{{FromInput=json.path}}} placeholders. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must fully disclose behavior. It states the tool downloads config from a URL and returns JSON, but omits important details such as network error handling, timeout limits, authentication, size restrictions, or what happens with invalid configs. This lack of transparency could lead to unexpected failures.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two concise sentences with no unnecessary words. It front-loads the action and result, then adds the key distinction from 'fitter_run'. Every sentence provides useful information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool involves remote fetching and parsing, but the description does not detail the return format beyond 'extracted data as JSON', nor does it explain error conditions or required permissions. With no output schema, more detail would be beneficial for an agent to anticipate the response structure.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already covers both parameters with descriptions (100% coverage). The description adds value by specifying the required top-level keys of the config ('item', 'limits', 'references'), which aids in understanding the expected structure beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool runs a Fitter config from an HTTP(S) URL and returns JSON data. It explicitly distinguishes itself from 'fitter_run' by noting the remote fetching behavior, making the purpose specific and differentiated from siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description indicates when to use this tool over 'fitter_run' (remote vs local config) and gives an example (raw GitHub link). However, it does not explicitly mention when not to use it or alternatives like 'fitter_run_file', though the context from the name and sibling list provides some guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fitter_validate_configA
Validate a Fitter config (JSON or YAML) without executing it. Checks the structural rules: item/connector_config/model presence, valid response_type, that the connector has a data source, and compiles every condition/item_condition expression in the model. Returns "valid" or the validation error. Cheap and safe — use it while iterating on a config before calling fitter_run.
| Name | Required | Description | Default |
|---|---|---|---|
| config | Yes | Fitter CliItem config as a JSON or YAML string to validate without executing it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully carries the burden, detailing what it checks (structural rules, condition compilation), that it is cheap and safe, and that it returns 'valid' or error. This comprehensively discloses behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, each earning its place: purpose, checks, and usage advice. Front-loaded and succinct with no redundancies.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the single parameter and no output schema, the description fully covers purpose, behavior, usage context, and return type. It is complete for effective tool selection.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description reinforces the config parameter but adds no new parameter-level details beyond the schema description.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states 'Validate a Fitter config (JSON or YAML) without executing it,' clearly specifying the verb and resource. It distinguishes from sibling tools like fitter_run by advising use before calling fitter_run.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly advises using this tool while iterating on a config before calling fitter_run, providing clear when-to-use context. However, it does not explicitly state when not to use it or mention alternatives for different scenarios.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
1 tool update
v1.8.2- Added
fitter_inspect_url
1 tool update
v1.7.0- Added
fitter_validate_config
4 tool updates
v0.1.0- First observed
fitter_config_reference - First observed
fitter_run - First observed
fitter_run_file - First observed
fitter_run_url
TDQS
Each tool serves a distinct purpose: reference, inspection, execution (with three source variants), and validation. No overlap or ambiguity between them.
All tools follow the 'fitter_' prefix with snake_case, and the action part is consistently descriptive (inspect, run, validate). The naming pattern is uniform and predictable.
Six tools is ideal for a config-driven scraping/parsing workflow: reference, inspect, run (three variants), and validate. Not bloated or sparse.
The toolset covers the full lifecycle: learning the format (reference), inspecting target structure (inspect), validating configs (validate), and executing from inline, file, or URL sources. No missing functionality apparent.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
MCP server for Riveter's enrichment, scraping, and monitoring API
MCP server for web extraction and rendering via AceDataCloud WebExtrator
One MCP server for 180+ live web-data APIs returning clean JSON from sites that block scrapers.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceMCP server for interacting with Prometheus metrics and data.17MIT
- AlicenseAqualityCmaintenanceAn MCP server for fetching and transforming web content into various formats.48MIT
- FlicenseBqualityDmaintenanceAn MCP Server for Web scraping and Crawling, built using Crawl4AI224-
- AlicenseAqualityCmaintenanceMCP server for web scraping — extract clean markdown, links, and metadata from any URL. Free Firecrawl alternative.51575MIT
Appeared in Searches
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/PxyUp/fitter'
If you have feedback or need assistance with the MCP directory API, please join our Discord server