Crawl4AI: установка на VPS
Если вам нужен не разовый скрапинг одной страницы, а регулярный сбор контента для базы знаний или RAG-системы, самописный парсер на requests и BeautifulSoup быстро упирается в JS-рендеринг, меню и рекламу в каждом чанке, а на выходе — сырой HTML, который ещё готовить и готовить перед тем как отдать модели. Crawl4AI закрывает именно этот разрыв: краулит как настоящий браузер и сразу отдаёт чистый markdown, готовый для эмбеддинга. Разберём установку на VPS через pip и Docker, первый рабочий скрипт и то, как вписать всё это в пайплайн RAG.
Содержание
- Crawl4AI против самодельного парсера: когда он оправдан
- Установка на VPS: подготовка и pip
- Docker-вариант: Crawl4AI как HTTP-сервис
- Первый скрипт: краулинг страницы и markdown на выходе
- Интеграция в RAG-пайплайн: от краулинга до векторной базы
- Тонкая настройка: JS, фильтрация мусора, извлечение по схеме
- Какой VPS брать под Crawl4AI
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Crawl4AI против самодельного парсера: когда он оправдан
Crawl4AI — открытый Python-фреймворк для краулинга, спроектированный конкретно под подготовку контента для LLM и RAG. Под капотом — Playwright с headless Chromium, то есть страница реально рендерится в браузере, а не запрашивается как голый HTML. Разница ощущается сразу на сайтах с React, Vue или Next.js: requests.get() там возвращает пустой <div id="root"></div>, а Crawl4AI дожидается отрисовки и забирает готовый DOM.
Второе отличие — формат результата. Обычный парсер отдаёт HTML или в лучшем случае текст, из которого ещё нужно вручную убирать шапку, меню, футер и баннер cookie-согласия. Crawl4AI на выходе сразу даёт markdown двух видов: raw_markdown — честный перевод HTML в markdown без изменений, и fit_markdown — та же страница после эвристической фильтрации шаблонных блоков. Для RAG обычно нужен именно второй вариант: меньше шума — выше точность поиска по эмбеддингам.
Когда самописный парсер всё ещё оправдан: если сайт один, вёрстка простая и статическая, а поля, которые нужно вытащить, известны заранее — пять строк на BeautifulSoup часто быстрее, чем поднимать браузерный движок. Crawl4AI выигрывает там, где источников много, вёрстка у них разная и меняется без предупреждения, а конечная цель — не пять конкретных полей, а связный текст для модели.
| Самописный парсер (requests + BeautifulSoup) | Crawl4AI | |
|---|---|---|
| JS-рендеринг | Не работает без отдельного добавления Selenium/Playwright | Встроен по умолчанию |
| Очистка от меню/рекламы | Вручную, под каждый сайт свои селекторы | Эвристика fit_markdown + свои фильтры |
| Формат вывода | HTML или сырой текст | Markdown, готовый под эмбеддинг |
| Массовый обход | Пишете сами: очередь, ретраи, параллелизм | arun_many() из коробки |
| Порог входа на одном простом сайте | Ниже | Требует настройки браузера |
Установка на VPS: подготовка и pip
Понадобится чистый VPS с Ubuntu 24.04 или Debian 12 — на них Python уже версии 3.11+, а Crawl4AI требует минимум 3.9. Подключаемся по SSH и ставим виртуальное окружение — на обеих системах системный pip install без него откажет ошибкой externally-managed-environment из-за PEP 668:
sudo apt update && sudo apt install -y python3-venv python3-pip
python3 -m venv ~/crawl4ai
source ~/crawl4ai/bin/activate
Дальше сам пакет и обязательная постустановка — она подтягивает бинарник headless Chromium под Playwright и без неё браузер просто не найдётся при первом запуске:
pip install -U crawl4ai
crawl4ai-setup
Если сервер совсем голый и системных библиотек для Chromium ещё нет, crawl4ai-setup может не докачать всё нужное — тогда playwright install-deps chromium от root добьёт зависимости через apt. Финальную проверку делает crawl4ai-doctor: команда прогоняет тестовый краулинг example.com и явно пишет, что не так — версия Python, браузер или сеть. Подробный разбор конкретных ошибок на этом шаге и их текстов — в отдельной статье про установку и настройку Crawl4AI, если что-то пошло не по плану.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать VPSDocker-вариант: Crawl4AI как HTTP-сервис
Пакет в venv удобен, пока краулер вызывает один Python-процесс на этом же сервере. Как только к нему должны обращаться разные клиенты — бэкенд, n8n, другой сервер в сети, — проще поднять готовый Docker-образ с HTTP API:
docker run -d --name crawl4ai \
-p 127.0.0.1:11235:11235 \
--shm-size=1g \
-e CRAWL4AI_API_TOKEN=$(openssl rand -hex 24) \
--restart unless-stopped \
unclecode/crawl4ai:latest
Два момента здесь не для галочки. --shm-size=1g — Docker по умолчанию выделяет контейнеру 64 МБ разделяемой памяти, а Chromium требует больше; без флага браузер молча падает на первой тяжёлой странице. И публикация порта именно на 127.0.0.1, а не 0.0.0.0, — сервис без токена слушает интернет без единой проверки, кто стучится; с заданным CRAWL4AI_API_TOKEN наружу его пускают уже через Nginx с TLS.
Проверка и запуск краулинга — обычные HTTP-запросы:
curl http://127.0.0.1:11235/health
curl -X POST http://127.0.0.1:11235/crawl \
-H "Authorization: Bearer <ваш-токен>" \
-H "Content-Type: application/json" \
-d '{"urls": ["https://example.com"], "crawler_config": {"cache_mode": "bypass"}}'
Актуальный список параметров и полную схему запроса удобнее смотреть в /playground самого контейнера — образ обновляется чаще, чем успевают переиздаваться сторонние мануалы.
Первый скрипт: краулинг страницы и markdown на выходе
Минимальный рабочий пример на чистом Python, без Docker — асинхронная функция вокруг AsyncWebCrawler:
import asyncio
from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode
async def main():
browser_conf = BrowserConfig(headless=True)
run_conf = CrawlerRunConfig(cache_mode=CacheMode.BYPASS)
async with AsyncWebCrawler(config=browser_conf) as crawler:
result = await crawler.arun(url="https://example.com/docs", config=run_conf)
print(result.markdown.fit_markdown[:1000])
asyncio.run(main())
Два нюанса, о которые почти все спотыкаются в первый раз. result.markdown — не строка, а объект с полями .raw_markdown и .fit_markdown, обращаться нужно именно так. И CacheMode.BYPASS — не опция для галочки: по умолчанию Crawl4AI кеширует результат по URL на диск, и при повторном запуске во время отладки вы получите старую версию страницы вместо свежего запроса.
Для обхода не одной страницы, а целого раздела сайта есть arun_many() — принимает список URL и параметр max_session_permit, ограничивающий число параллельных браузерных контекстов:
async def crawl_section(urls: list[str]):
run_conf = CrawlerRunConfig(cache_mode=CacheMode.BYPASS)
async with AsyncWebCrawler() as crawler:
results = await crawler.arun_many(urls, config=run_conf, max_session_permit=3)
return [r.markdown.fit_markdown for r in results if r.success]
На VPS с 2 ГБ RAM max_session_permit больше 2 почти гарантированно уводит процесс в OOM — каждый браузерный контекст держит свои сотни мегабайт, независимо от того, насколько простая страница.
Интеграция в RAG-пайплайн: от краулинга до векторной базы
Место Crawl4AI в пайплайне RAG — самый первый шаг, сбор и очистка сырых данных, тот самый, который в статье про сбор данных для RAG парсингом сайтов закрывают связкой из sitemap-обхода и trafilatura. Crawl4AI решает ту же задачу иначе: рендерит JS-страницы из коробки и сразу возвращает готовый markdown, так что отдельный шаг «извлечь текст из HTML» из пайплайна выпадает целиком.
Дальше пайплайн одинаковый вне зависимости от того, чем вы получили текст:
- Краулинг — Crawl4AI обходит список URL (из sitemap.xml или руками составленного списка страниц) и отдаёт markdown по каждой.
- Чанкинг — делите текст на куски по 300–800 токенов с небольшим перекрытием, желательно по границам заголовков и абзацев, а не «по количеству символов вслепую».
- Эмбеддинги — каждый чанк превращается в вектор моделью эмбеддинга; какую модель брать под свою задачу и язык — отдельный вопрос, разобран в статье про выбор модели эмбеддингов для RAG.
- Векторная база — векторы вместе с исходным текстом и метаданными (URL, заголовок, дата обхода) уходят в индекс, например Qdrant.
Каркас на Python — от результата arun_many() до записи в Qdrant:
from qdrant_client import QdrantClient
from qdrant_client.models import PointStruct
import uuid
client = QdrantClient(url="http://127.0.0.1:6333")
def chunk_text(text: str, size: int = 500, overlap: int = 50) -> list[str]:
words = text.split()
chunks = []
for i in range(0, len(words), size - overlap):
chunks.append(" ".join(words[i:i + size]))
return chunks
async def index_page(crawler, url: str, embed_fn):
result = await crawler.arun(url=url, config=CrawlerRunConfig(cache_mode=CacheMode.BYPASS))
if not result.success:
return
chunks = chunk_text(result.markdown.fit_markdown)
points = [
PointStruct(id=str(uuid.uuid4()), vector=embed_fn(c), payload={"url": url, "text": c})
for c in chunks
]
client.upsert(collection_name="docs", points=points)
embed_fn здесь — заглушка под вашу модель эмбеддинга, локальную через sentence-transformers или облачную по API; сам вызов Qdrant не зависит от того, откуда взялся вектор. Разворачивать Qdrant на том же VPS, где стоит Crawl4AI, или на соседнем сервере — вопрос нагрузки; для старта достаточно одного сервера на обоих, подробности — в статье про установку Qdrant на VPS.
Важный практический момент: сайт меняется, и разовый обход устаревает. Повторный краулинг по расписанию (cron или systemd timer) с перезаписью точек по url в payload — рабочая схема без переусложнения; полноценную инкрементальную синхронизацию с отслеживанием измененных страниц стоит городить, только если объём документов уже реально большой.
Тонкая настройка: JS, фильтрация мусора, извлечение по схеме
BrowserConfig и CrawlerRunConfig — два места, где настраивается почти всё поведение краулинга. Из полезного для подготовки данных под RAG:
- Ожидание динамического контента. Если страница подгружает данные не сразу, а через пару секунд после рендера (инфинити-скролл, ленивая загрузка), в
CrawlerRunConfigесть параметры ожидания по селектору или задержки — без них Crawl4AI может забрать страницу раньше, чем нужный блок появился в DOM. - Исключение навигации и рекламы. Помимо автоматической эвристики
fit_markdown, можно явно указать CSS-селекторы блоков, которые не нужно включать в результат — шапку, футер, баннеры согласия на cookie, — если эвристика по умолчанию их не убрала. - Извлечение по CSS-схеме вместо markdown. Когда нужны не связный текст, а конкретные поля — цена, заголовок, дата, —
JsonCssExtractionStrategyописывает схему селекторов и возвращает готовый JSON вместо markdown; полезно, когда часть страниц вашего источника — карточки товаров или структурированные записи, а не статьи. - LLM-извлечение.
LLMExtractionStrategyпрогоняет текст через языковую модель по вашему промпту — годится для более сложной нормализации данных, но требует ключа провайдера (OPENAI_API_KEYили аналог) либо локальной модели через Ollama на том же сервере, и заметно дороже по времени, чем обычный markdown-краулинг.
Актуальный список всех параметров стоит сверять с документацией проекта на GitHub — фреймворк активно развивается, и часть флагов между релизами переименовывается или меняет поведение по умолчанию.
Какой VPS брать под Crawl4AI
Нагрузка здесь браузерная, не вычислительная: Chromium ест RAM на каждый контекст, а CPU почти всегда простаивает. Ориентир по конфигурациям:
| Задача | vCPU | RAM | Диск |
|---|---|---|---|
Тесты, единичные страницы, max_session_permit=1 | 2 | 4 ГБ | 40 ГБ NVMe |
| Docker-сервис на несколько клиентов, обход сотен страниц | 4 | 8 ГБ | 80 ГБ NVMe |
| Краулинг + локальная LLM-экстракция через Ollama на том же сервере | 8 | 16 ГБ | 100 ГБ NVMe |
Ниже 4 ГБ RAM конфигурацию сложно рекомендовать даже для теста — уже пара параллельных браузерных контекстов на многостраничном сайте способна упереться в OOM. Локацию стоит выбирать по тому, куда вы обходите и куда потом стучится LLM для извлечения: если источники и провайдер эмбеддингов/LLM зарубежные, сервер за пределами России — в Лондоне или США — даёт короче маршрут и снимает вопросы с региональными ограничениями по IP у некоторых облачных LLM-провайдеров. Если обходите только рунет, а модель эмбеддингов локальная, разница обычно не критична.
Готовых сборок Crawl4AI в каталоге приложений нет — сервер приходит чистым, а установка занимает пару команд из раздела выше. Зато Qdrant и Ollama, если пайплайн включает их, разворачиваются одной кнопкой из панели — не придётся настраивать их отдельно.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать VPSОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Чем Crawl4AI отличается от Firecrawl?
Firecrawl — облачный сервис с API и лимитами по подписке, Crawl4AI — библиотека с открытым кодом, которую вы разворачиваете сами; нет платы за страницу и внешнего журнала ваших запросов, но и инфраструктуру поддерживаете сами.
Обязательно ли использовать Docker, или venv для одного скрипта достаточно?
Для регулярного вызова из одного Python-процесса на этом же сервере venv полностью достаточно. Docker имеет смысл, когда к краулеру должны обращаться несколько разных сервисов по HTTP.
Можно ли использовать Crawl4AI без LLM вообще, просто для получения текста?
Да, базовый краулинг с выводом raw_markdown/fit_markdown не требует никакого LLM-ключа — LLM нужен только для стратегии LLMExtractionStrategy, отдельного и опционального шага.
Как часто нужно перекраулить сайт для RAG?
Зависит от того, как часто меняется источник — для документации продукта обычно достаточно раз в сутки-неделю по cron, для новостного контента чаще. Отслеживать last-modified в sitemap.xml помогает не перекраулить страницы без изменений.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.