# Trawls — www.trawls.dev Moteur de crawling, d'extraction et de navigation web, construit from scratch. Un chalut (*trawl*) ratisse le fond et remonte tout : Trawls cartographie et extrait n'importe quel site et renvoie du **Markdown propre, LLM-ready**. - **Ne crashe jamais** : une page qui échoue produit un `PageResult` `status=failed` avec une erreur typée. Le crawl continue. - **Escalade automatique** : HTTP pur (curl_cffi, empreinte TLS Chrome) → navigateur (Playwright, pool de contexts) → stealth (patches JS, identité cohérente). Le mode résolu est mémorisé par host. - **Sortie LLM-ready** : pipeline HTML → Markdown maison (nettoyage, suppression du boilerplate, scoring du contenu principal, tables avec rowspan/colspan, citations), métadonnées fusionnées (head, OpenGraph, JSON-LD), chunks par titres ou par tokens. - **PDF** : texte avec ordre de lecture, titres inférés, tables, détection de scan (OCR optionnel). - **Extraction structurée** : CSS typé (déterministe) ou LLM (JSON Schema, validation, corrections) avec fusion multi-pages. - **Self-host first** : SQLite, worker embarqué, aucun service externe requis. LLM local via Ollama par défaut. - **Observable** : structlog JSON, `/healthz`, `/readyz`, `/metrics` Prometheus, trace d'escalade par page. ## Démarrage ```bash uv venv --python 3.12 && source .venv/bin/activate uv pip install -e ".[dev]" playwright install chromium trawls serve # http://localhost:8180 (UI + API + worker) ``` ```bash trawls scrape https://fr.wikipedia.org/wiki/Chalut trawls map https://docs.python.org --search "asyncio" trawls crawl https://exemple.com --max-pages 50 -o pages.jsonl ``` Docker : `make up` (api + web sur http://localhost:8180). ## API (`/v1`, OpenAPI sur `/docs`) | Méthode | Route | Rôle | |---|---|---| | POST | `/scrape` | une page, synchrone → `PageResult` | | POST | `/crawl` → GET `/crawl/{id}` · `/crawl/{id}/stream` (SSE) · DELETE | crawl asynchrone, pages streamées | | POST | `/map` | liste d'URLs (sitemaps + crawl shallow), tri BM25 si `search` | | POST | `/extract` | CSS ou LLM sur `urls[]` / `pattern` ; sync ≤ 5 URLs | | POST | `/batch/scrape` | N URLs en job | | GET | `/jobs`, `/jobs/{id}`, `/jobs/{id}/stream`, `/jobs/{id}/export?format=zip\|jsonl\|md` | jobs génériques | | GET | `/usage` · `/keys` (admin) | crédits, clés API (argon2, affichées une fois) | Erreurs : `{ "error": { "code", "message", "retryable", "details?" } }`. Idempotence : header `Idempotency-Key`. Webhooks signés `X-Trawls-Signature` (HMAC-SHA256). ```bash curl -s https://www.trawls.dev/v1/scrape -H 'Content-Type: application/json' \ -d '{"url":"https://example.com","formats":["markdown","links"]}' | jq .markdown ``` ## Configuration (préfixe `TRAWLS_`) `PORT` (8180), `PUBLIC_URL`, `DATA_DIR`, `REQUIRE_AUTH`, `ADMIN_KEY`, `BROWSER_POOL_SIZE`, `MAX_CONCURRENCY_PER_HOST`, `MAX_SIZE_MB`, `PROXY_URLS`, `LLM_PROVIDER` (`openai`|`anthropic`|`none`), `LLM_BASE_URL` (Ollama par défaut), `LLM_API_KEY`, `LLM_MODEL`, `RESULT_TTL_DAYS`, `RATE_LIMIT_PER_MINUTE`, `ALLOW_PRIVATE_TARGETS` (jamais en prod). Voir `.env.example`. ## Architecture ``` trawls/ config.py settings pydantic models/ contrat Pydantic v2 (ScrapeOptions, PageResult, ErrorInfo…) core/fetcher/ http_fast (curl_cffi), browser (pool Playwright), strategy (escalade) core/antibot/ detect, identity, stealth, blocklist core/scheduler/ dedup (normalisation + simhash), robots, politeness core/resilience/ retry, breaker, budget core/security.py garde SSRF (DNS résolu avant, re-vérifié après redirection) core/scrape.py pipeline d'une page — ne lève jamais processors/ html_to_md (clean, readability, convert, tables, citations), pdf, structured, chunker, links extract/ css, llm, merge map/ sitemaps + crawl shallow + BM25 llm/ client unique (Anthropic, OpenAI-compatible) worker/ store SQLite, moteur de jobs (crawl/batch/extract), SSE api/ FastAPI /v1, auth, UI web/static/ UI (playground, crawls, map, extract, keys) cli.py ``` ## Tests ```bash pytest -q # unitaires (html_to_md, dedup, ssrf, detect, chunker, css) ruff check . && ruff format --check . ``` ## Déploiement MacLustr Déployée via `mld` (manifeste `trawls.json`) : PM2 `trawls-api` + `trawls-ngrok` → https://www.trawls.dev. Voir `deploy/trawls.manifest.json`. ## Feuille de route Phases 1–6 livrées (fetch + escalade, Markdown, API/jobs/SSE/CLI, map + PDF, extract + chunker, UI). Phase 7 (agent) et 8 (SDK, benchmarks) à venir — voir `CLAUDE.md`.