Где боль
Любой агент, который ходит по URL — Claude Code с web-fetch, Pi с tavily-extract, локальный RAG, ночной краулер документации — упирается в один и тот же вопрос: что именно скармливать модели. Сырой HTML страницы — самый честный вариант, но cloudflare на одном посте намерял 16 180 токенов HTML против 3 150 токенов Markdown — минус 80%. На длинной сессии это превращается в реальные деньги и в распухший контекст, в котором модель начинает терять нить.
Альтернатива — конвертировать HTML в Markdown заранее. Но «конвертировать» здесь скрывает два разных шага: вычленить main content (выкинуть навигацию, футер, сайдбары, cookie-баннеры) и собственно перевести оставшийся HTML в Markdown с сохранением структуры. Если делать только второй шаг, F1 относительно «человеческого» Markdown падает до 0.5–0.66 — то есть половина вывода окажется мусором, который не нужен ни модели, ни читателю. Если делать только первый — получаешь чистый, но неструктурированный текст без таблиц и code fences.
Поэтому реальный выбор — это не «какой конвертер взять», а «какая связка извлечения + конвертации работает на твоих страницах». И связок четыре.
Четыре подхода
- Локальные эвристики. Trafilatura, Readability.js, Defuddle, Resiliparse. Парсят DOM, удаляют «unlikely candidates» по class/id, скорят секции по text density, отдают main content. Trafilatura умеет Markdown сразу, остальные — нужен Turndown/markdownify сверху. Без браузера: на SPA-страницах увидят пустой shell.
- Локальные краулеры с extract-слоем. Crawl4AI (Playwright + PruningContentFilter), Scrapy + Trafilatura, Browserless с Turndown. Те же эвристики, но с реальным JS-рендерингом и control над сетью.
- Хостинговые API. Jina Reader (
r.jina.ai/<URL>), Firecrawl, ScrapingBee, Zyte. Берут на себя headless Chrome, прокси-пул, anti-bot. Отдают Markdown через HTTP. Данные уходят к вендору; цена считается в страницах или токенах. - LLM-ассистированная экстракция. Jina ReaderLM-v2 (1.5B, локально или через API), IBM Granite-Docling-258M, Docling. Модель смотрит на HTML и переводит его в Markdown целиком, сохраняя code fences, таблицы и LaTeX. Медленнее эвристик в разы, дороже в 3× токенов на API, но единственный реалистичный путь для сложной разметки.
Главный компромисс: (1) самый дешёвый и приватный, но ломается на JS-страницах; (2) добавляет браузер; (3) перекладывает всю инфру на чужой SLA; (4) лучше всех держит структуру, но медленный.
Когда что выбирать
- По умолчанию для блогов, статей, новостей. Trafilatura. На независимых бенчмарках лидер: F1 0.88 (SIGIR 2023, среднее по 8 датасетам), 0.945 на ScrapingHub article-extraction-benchmark. Натив-выход в Markdown, метаданные (title/author/date) бесплатно.
trafilatura --output-format markdown --include-links --include-tables --include-formatting. - Современные SPA с кодом, формулами, footnotes. Defuddle (kepano, ядро Obsidian Web Clipper). Multi-pass извлечение, нормализация code blocks с
data-lang, MathML→LaTeX черезtemml, footnotes в стандартный[^N]— то, чего Readability и Trafilatura не умеют. - Docs-сайты с большими таблицами и API-референсами. Crawl4AI с PruningContentFilter, либо Docling если таблицы критичны. Trafilatura теряет sidebar-TOC и иногда комкает rowspan/colspan.
- Одиночный URL без своей инфры. Jina Reader: префикс
r.jina.ai/к URL, headless Chrome + Readability + Turndown под капотом, бесплатный анонимный доступ. Средняя задержка ~7.9 s. - Краулинг сайта целиком. Firecrawl: scrape + crawl + map в одном API, MCP-сервер, кэш. 1 credit/страница, AGPL-3.0 для self-host.
- Anti-bot сайты (Cloudflare, Akamai, paywall). Не Firecrawl — на 15 защищённых сайтах при 2 req/s он показал 33.69% success (Proxyway). Zyte (93%) или Scrapfly (98%).
- Сложные таблицы / LaTeX / code fences с языком — критично. ReaderLM-v2 локально. По собственной оценке Jina бьёт Qwen2.5-32B и Gemini-2-flash на HTML→Markdown; ROUGE-L 0.84 при 1.5B параметров.
- Контент критически зависит от ARIA/widget/SVG/MathML, агент сам должен решать что важно. Сырой HTML, минуя конвертер. Оплата токенами; формат промпта меняет качество LLM на code-tasks до 40% (arXiv 2411.10541).
Где живёт пайплайн на каждом подходе
| Подход | Извлечение | Конвертация | JS-рендер |
|---|---|---|---|
| Trafilatura | tree pruning + content scoring | натив Markdown | нужен внешний |
| Defuddle + Turndown | multi-pass + mobile-CSS | Turndown | parseAsync |
| Crawl4AI | PruningContentFilter | DefaultMarkdownGenerator | встроен Playwright |
| Jina Reader API | Readability | Turndown | headless Chrome у Jina |
| Firecrawl API | свой extractor | свой | свой |
| ReaderLM-v2 | модель решает обе задачи | вместе | нужен внешний |
| Docling | DocTags + конвертер | натив Markdown | n/a |
Что под капотом каждого подхода
Локальные эвристики
Trafilatura (adbar, Python + Rust-порт rs-trafilatura) — гибридный пайплайн: lxml-парсинг → tree pruning по «гарантированно не main» (nav/footer/aside) → скоринг секций по text density, link density, типам тегов → fallback на readability-lxml и justext, если основной алгоритм вернул пусто. Натив-выходы: text, Markdown, HTML, XML, XML-TEI, JSON, CSV. Лицензия Apache-2.0, ACL-2021 (Barbaresi).
Readability.js (Mozilla, ядро Firefox Reader View) — алгоритм проще: удаление «unlikely candidates» по class/id, скоринг секций по text density, выбор top-кандидата. Высокая медиана F1 (0.97 в SIGIR), но «too aggressive» — иногда вырезает полезное, не нормализует footnotes/code/math. Не отдаёт Markdown сам — нужен Turndown сверху. Считается «mostly abandoned» в комьюнити, хотя обновления есть.
Defuddle (kepano, MIT, 2025) — позиционируется как Readability 2.0. Multi-pass: если первый проход вернул пусто, ослабляет критерии и пробует ещё раз. Анализирует mobile-стили как сигнал «не основной контент». Site-specific extractors для ChatGPT, Claude, Gemini, HN, Reddit. Главное преимущество — нормализация код-блоков (без line-numbers и подсветочных span’ов, с data-lang), MathML→LaTeX, footnotes в стандартный формат. Это критично для качества Markdown в RAG.
Resiliparse (chatnoir-eu) — C-extension, очень быстрый. Используется в NVIDIA NeMo-Curator и DCLM-Baseline для предобучения LLM на 2.6T токенов веба. Узкий фокус, но рабочая лошадь для масштабов.
Crawl4AI
50k+★ на GitHub, Apache-2.0. Headless через Playwright, DefaultMarkdownGenerator + PruningContentFilter/BM25ContentFilter/LLMContentFilter на выбор. Различает fit_markdown (отфильтрованный) и raw_markdown. Citations/references-режим. Adaptive crawling — информац.-добывающая эвристика, по сторонним тестам ~40% быстрее на FAQ/docs. Поддержка LLM-extraction через LiteLLM (OpenAI/Anthropic/Ollama). Лучший выбор, если нужен self-host + JS-рендер в одном пакете.
Jina Reader
r.jina.ai/<URL> — URL-префикс, ничего настраивать не нужно. Под капотом headless Chrome → Readability → Turndown. Заголовки управляют поведением: x-engine: readerlm-v2 переключает на LLM-модель, x-engine: browser — форсит JS-рендер, x-proxy: auto — поднимает прокси-пул. s.jina.ai/<query> — search-mode. Free tier ~10M токенов, дальше ~$0.045/1M токенов. Apache-2.0, self-host (10k+★).
Firecrawl
Полный crawler в одном API: scrape, crawl, map, search, extract. JSON-schema extract — задаёшь схему, получаешь структурированные данные напрямую. Кэш до 5× быстрее повторных запросов. MCP-сервер. Hobby $16/3k credits, Standard $83/100k. AGPL-3.0 — fork/self-host обязывает раскрывать модификации. Для closed-source продуктов это релевантный риск; Jina Reader под Apache-2.0 — без ограничений.
LLM-ассистированные модели
ReaderLM-v2 (Jina, Qwen2.5-1.5B base, Apache-2.0). 1.5B параметров, 512K контекст, 29 языков. Идея — не «выбрать что копировать», а «перевести HTML в Markdown как с одного языка на другой». На собственной оценке Jina даёт ROUGE-L 0.84, Levenshtein 0.22 и обходит Qwen2.5-32B-Instruct и Gemini-2-flash-expr. Через Jina-API стоит в 3× обычного количества токенов. Локально — крутится на CPU.
Granite-Docling-258M (IBM, 2025). 258M VLM. Сначала переводит документ в формат DocTags — внутреннее структурное представление, сохраняющее layout, таблицы, формулы — потом конвертирует в Markdown/JSON/HTML без потерь. Многоформатный (PDF/HTML/документы). Air-gapped.
Docling (LF AI & Data Foundation). Python-библиотека и сервер. HTML/PDF/DOCX/PPTX/Markdown, native экспорт в Markdown/HTML/JSON, чанкование под RAG. Использовался для обработки 2.1M PDF из Common Crawl для InstructLab. Тяжёлый: ~34 s на одну PDF-страницу в одном из тестов.
Что НЕ брать
MarkItDown (Microsoft, ~95k★) — универсальный конвертер для PDF/DOCX/PPTX/XLSX/EPUB/YouTube. Для HTML внутри использует BeautifulSoup + Markdownify и не вычленяет main content. На веб-странице с навигацией он передаст в Markdown навигацию, футер и сайдбары. Не используйте его как замену Readability/Trafilatura для скачанных URL.
Чистый html2text / markdownify / Pandoc на сырой странице. F1 0.5–0.66 относительно gold-standard Markdown. Эти инструменты предполагают, что HTML уже очищен.
Fallback-цепочка
- Trafilatura. Если результат валидный (длина > N слов, нет явного мусора) — стоп.
- Если страница — современный SPA или статья с кодом → Defuddle.
- Если docs-сайт с таблицами → Crawl4AI fit_markdown или Docling.
- Если страница пустая (SPA-shell, заблокирован anti-bot) → Jina Reader с
x-engine: browser,x-proxy: auto. - Если успех < 70% (anti-bot) → Zyte/Scrapfly как unblocking-слой, потом любая эвристика поверх.
- Если критичны сложные code fences/LaTeX/nested tables и бюджет позволяет → ReaderLM-v2 локально или через
x-engine: readerlm-v2. - Сырой HTML → только если контент критически зависит от ARIA/widget/SVG, которые конвертеры теряют, либо для агентов с computer-use, которым нужно решать самим.
Пороги, при которых надо переключаться
- F1 vs gold < 0.85 на ваших страницах при Trafilatura — попробовать Defuddle или Crawl4AI fit_markdown.
- Сохранённых code-блоков < 90% — Defuddle или ReaderLM-v2.
- Сохранённых таблиц < 80% — Docling/Granite-Docling или ReaderLM-v2.
- Стоимость LLM-токенов из-за HTML растёт — Markdown даёт −80% (Cloudflare).
- Success rate на anti-bot < 70% — переходить с Firecrawl/Crawl4AI на Zyte/Scrapfly.
- Privacy-критичные данные (медицина, финансы, корп.docs) — только локально: Playwright+Trafilatura, Docling, ReaderLM-v2. Не отправлять в r.jina.ai/firecrawl.dev.
Оговорки
- Большинство сравнительных цифр — самооценки вендоров. Числа Firecrawl («F1 0.638, 96% coverage на 1000 URL») и Jina («ReaderLM-v2 бьёт GPT-4 и Gemini») берите как ориентир, не как нейтральную истину.
- Бенчмарки Bevendorff (SIGIR 2023) и ScrapingHub старели не одинаково. Версии библиотек 2021–2023; trafilatura и crawl4ai активно эволюционируют (текущие — 2.x и 0.8.x). Абсолютные цифры могут отличаться.
- Препринт arXiv 2511.23119 (Dripper SLM) показывает Trafilatura/Resiliparse с F1 0.63–0.64, что противоречит SIGIR и ScrapingHub (0.88–0.94). Возможные причины — иной gold-standard и определение «main content». Не использовать как опорные числа без независимой проверки.
- Публично нет ни одного независимого бенчмарка специально для связки «HTML → Markdown с сохранением code-блоков, сложных таблиц и вложенных списков». Если выбор критичен — стройте свой бенчмарк хотя бы на 100 ваших страниц с ручным gold-standard.
- Anti-bot и cookie-баннеры на новостных сайтах ЕС/UK часто маскируются под «пустой» контент даже после рендера — отсюда «Reader View» иногда выдаёт пустую страницу. Лечится pre-cleanup селекторами modal-overlay перед extractor’ом.