Как скормить нейросети любую страницу без рекламного мусора и лишних токенов
Когда отдаешь LLM-агенту обычный веб-скрейпинг, в контекст мгновенно улетают тонны навигационных меню, футеров, баннеров и простыней разметки. Вместе со статьей на пару тысяч слов агент получает мегабайт мусора, контекстное окно забивается, а счет за токены растет.
Недавно наткнулся на проект pullmd. Это self-hosted сервис, который принимает ссылку на страницу или файл и возвращает аккуратный Markdown. Без лишнего обвеса, без дублирования метаданных в тексте и с парой фич, которых часто не хватает в стандартных библиотеках парсинга.
Что под капотом
Создатели проекта собрали вместе несколько проверенных инструментов. Когда на вход поступает ссылка, сервис сначала проверяет наличие нативного Markdown от Cloudflare. Если его нет, в дело идут Mozilla Readability и Trafilatura.
Бывает, что страница полностью собрана на React или Vue и голый HTML возвращает пустой шаблон. В таких ситуациях pullmd подключает сайдкар с Playwright, рендерит страницу в headless Chromium и уже оттуда достает контент. Если тяжелый браузер не нужен, контейнер с Playwright можно просто выключить из docker-compose.yml, освободив около 3.7 ГБ места на диске. В этом случае сервис продолжит работать через обычный статический парсинг.
Все результаты оседают в локальной базе SQLite. Если запросить тот же URL в течение часа, ответ вернется мгновенно из кэша. Каждой конвертации присваивается постоянный короткий идентификатор, поэтому ссылку вида /s/:id можно использовать как стабильный фид.
Главные фичи, которые экономят время
Ветки Reddit и Hacker News
Обычно скрипты спотыкаются на страницах с комментариями. Здесь парсер специально обучен разбирать треды Reddit и Hacker News. На выходе получается структурированное дерево комментариев с сохранением вложенности, авторов и количества апвоутов.
Поиск по странице через BM25
Одна из самых удачных находок в третьей версии сервиса. Если в запросе передать параметр ?query=как настроить базу, pullmd не станет возвращать всю многостраничную документацию. Сервис разбивает Markdown на секции по заголовкам, ранжирует их через алгоритм BM25 и отдает только те блоки, которые отвечают на вопрос. Для больших страниц это срезает от 70% до 95% токенов, что заметно ускоряет работу агентов. Таблицы и блоки кода при этом не разрезаются на части.
Документы, видео и аудио
Сервис умеет работать не только с сайтами. Если подключить сайдкар на базе MarkItDown от Microsoft, сервис переваривает PDF, файлы Word, Excel, PowerPoint и электронные книги EPUB.
Если передать ссылку на YouTube, сервис достанет расшифровку видео с кликабельными таймкодами без всяких API-ключей. Для распознавания изображений и аудио можно прописать эндпоинт любой OpenAI-совместимой модели или локального сервера вроде Ollama.
Встроенный MCP-сервер и интеграции
Для подключения к агентам предусмотрено сразу несколько вариантов:
- обычный REST API (
GET /api?url=...) - MCP-сервер для Cursor, Claude Desktop и других совместимых клиентов
- готовый плагин для Claude Code
- веб-интерфейс в формате PWA с возможностью перетаскивания файлов прямо из проводника
Безопасность и защита от SSRF
Сервисы, которые скачивают данные по произвольным ссылкам, уязвимы к SSRF-атакам. Пользователь может скормить парсеру внутренний адрес локальной сети или метаданные облачного провайдера.
В pullmd встроен механизм проверки адресов. Перед каждым запросом и на каждом шаге редиректа резолвятся IP-адреса хоста. Если адрес попадает в диапазоны приватных сетей, loopback, CGNAT или облачных метаданных вроде 169.254.169.254, запрос сразу блокируется с ошибкой 403. Если нужно намеренно открыть доступ к внутренней вики, адреса вносятся в белый список через переменную окружения PULLMD_ALLOWED_HOSTS.
Как развернуть у себя
Для базового запуска достаточно одного файла docker-compose.yml:
mkdir pullmd && cd pullmd
curl -O https://raw.githubusercontent.com/AeternaLabsHQ/pullmd/main/docker-compose.yml
docker compose up -d
Сервис поднимется на порту 3000. Авторизация по умолчанию отключена, но ее можно настроить: поддерживается как режим с одним администратором, так и многопользовательский режим с регистрацией и сессионными cookie.
Пример простого запроса к API:
curl "http://localhost:3000/api?url=https://news.ycombinator.com/item?id=1"
Для подключения к Claude Code достаточно одной команды:
claude mcp add --transport http pullmd http://localhost:3000/mcp
Кому пригодится
Проект получился аккуратным и практичным. У него пока меньше пятисот звезд на GitHub, но кодовая база выглядит зрело: чистая модульная структура, подробный файл миграции и минимум внешних зависимостей в основном контейнере.
Инструмент подойдет тем, кто строит RAG-пайплайны, настраивает локальных AI-ассистентов или просто хочет иметь под рукой удобную читалку длинных статей в формате Markdown. Если вы используете Cursor или Claude Code и часто просите их изучить документацию по ссылке, локальный инстанс pullmd сэкономит вам немало контекста и нервов.
