Python 76.2%
JavaScript 11.3%
CSS 6.3%
HTML 5.9%
1# Trawls — www.trawls.dev23Moteur 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**.45- **Ne crashe jamais** : une page qui échoue produit un `PageResult` `status=failed` avec une erreur typée. Le crawl continue.6- **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.7- **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.8- **PDF** : texte avec ordre de lecture, titres inférés, tables, détection de scan (OCR optionnel).9- **Extraction structurée** : CSS typé (déterministe) ou LLM (JSON Schema, validation, corrections) avec fusion multi-pages.10- **Self-host first** : SQLite, worker embarqué, aucun service externe requis. LLM local via Ollama par défaut.11- **Observable** : structlog JSON, `/healthz`, `/readyz`, `/metrics` Prometheus, trace d'escalade par page.1213## Démarrage1415```bash16uv venv --python 3.12 && source .venv/bin/activate17uv pip install -e ".[dev]"18playwright install chromium19trawls serve # http://localhost:8180 (UI + API + worker)20```2122```bash23trawls scrape https://fr.wikipedia.org/wiki/Chalut24trawls map https://docs.python.org --search "asyncio"25trawls crawl https://exemple.com --max-pages 50 -o pages.jsonl26```2728Docker : `make up` (api + web sur http://localhost:8180).2930## API (`/v1`, OpenAPI sur `/docs`)3132| Méthode | Route | Rôle |33|---|---|---|34| POST | `/scrape` | une page, synchrone → `PageResult` |35| POST | `/crawl` → GET `/crawl/{id}` · `/crawl/{id}/stream` (SSE) · DELETE | crawl asynchrone, pages streamées |36| POST | `/map` | liste d'URLs (sitemaps + crawl shallow), tri BM25 si `search` |37| POST | `/extract` | CSS ou LLM sur `urls[]` / `pattern` ; sync ≤ 5 URLs |38| POST | `/batch/scrape` | N URLs en job |39| GET | `/jobs`, `/jobs/{id}`, `/jobs/{id}/stream`, `/jobs/{id}/export?format=zip\|jsonl\|md` | jobs génériques |40| GET | `/usage` · `/keys` (admin) | crédits, clés API (argon2, affichées une fois) |4142Erreurs : `{ "error": { "code", "message", "retryable", "details?" } }`. Idempotence : header `Idempotency-Key`. Webhooks signés `X-Trawls-Signature` (HMAC-SHA256).4344```bash45curl -s https://www.trawls.dev/v1/scrape -H 'Content-Type: application/json' \46 -d '{"url":"https://example.com","formats":["markdown","links"]}' | jq .markdown47```4849## Configuration (préfixe `TRAWLS_`)5051`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`.5253## Architecture5455```56trawls/57 config.py settings pydantic58 models/ contrat Pydantic v2 (ScrapeOptions, PageResult, ErrorInfo…)59 core/fetcher/ http_fast (curl_cffi), browser (pool Playwright), strategy (escalade)60 core/antibot/ detect, identity, stealth, blocklist61 core/scheduler/ dedup (normalisation + simhash), robots, politeness62 core/resilience/ retry, breaker, budget63 core/security.py garde SSRF (DNS résolu avant, re-vérifié après redirection)64 core/scrape.py pipeline d'une page — ne lève jamais65 processors/ html_to_md (clean, readability, convert, tables, citations), pdf, structured, chunker, links66 extract/ css, llm, merge67 map/ sitemaps + crawl shallow + BM2568 llm/ client unique (Anthropic, OpenAI-compatible)69 worker/ store SQLite, moteur de jobs (crawl/batch/extract), SSE70 api/ FastAPI /v1, auth, UI71 web/static/ UI (playground, crawls, map, extract, keys)72 cli.py73```7475## Tests7677```bash78pytest -q # unitaires (html_to_md, dedup, ssrf, detect, chunker, css)79ruff check . && ruff format --check .80```8182## Déploiement MacLustr8384Déployée via `mld` (manifeste `trawls.json`) : PM2 `trawls-api` + `trawls-ngrok` → https://www.trawls.dev. Voir `deploy/trawls.manifest.json`.8586## Feuille de route8788Phases 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`.89