Настройка прокси в Crawl4AI

Прокси в Crawl4AI: ProxyConfig с логином и паролем в CrawlerRunConfig, страна в логине, порт 823 для отдельных страниц и фиксированный IP для сессии.

Обновлено · Редакция Prokso

Данные для подключения
Хост
gw.prokso.com
Порт
823 HTTP · 824 SOCKS5 — новый IP на каждый запрос · 10000–20000 фиксированный IP (sticky-сессия), HTTP(S) и SOCKS5
Логин и пароль
в кабинете, на странице плана

Готовые строки в нужном формате генерирует кабинет: выберите страну, тип IP и протокол.

Коротко
  • Хост — gw.prokso.com, порты 823 (HTTP), 824 (SOCKS5), 10000–20000 (фиксированный IP, HTTP или SOCKS5)
  • Логин и пароль — в кабинете на странице плана
  • Проверяйте IP в ответе самого запроса через прокси: страница «Мой IP» в браузере ваш скрипт не проверяет

Пошаговая инструкция, как подключить прокси Prokso в Crawl4AI. Займёт несколько минут.

Шаг 1. Возьмите данные прокси в кабинете

Откройте план и скопируйте хост gw.prokso.com, порт, логин и пароль. Порт 823 — HTTP, 824 — SOCKS5 (оба дают новый IP на каждый запрос); порты 10000–20000 — фиксированный IP до 120 минут, работают и как HTTP, и как SOCKS5 (каждый порт — отдельный адрес). Страну задают в логине: логин__cr.ua.

Шаг 2. Установите Crawl4AI

pip install -U crawl4ai, затем crawl4ai-setup — эта команда ставит браузер, которым Crawl4AI открывает страницы. Проверить установку можно командой crawl4ai-doctor. Инструкция написана для версии 0.9.5.

import asyncio
from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, ProxyConfig

run_config = CrawlerRunConfig(
    proxy_config=ProxyConfig(
        server="http://gw.prokso.com:823",
        username="ЛОГИН",
        password="ПАРОЛЬ",
    )
)


async def main():
    async with AsyncWebCrawler(config=BrowserConfig()) as crawler:
        result = await crawler.arun(url="https://api.ipify.org", config=run_config)
        print(result.success, result.markdown)


asyncio.run(main())

Сохраните код в файл, например crawl.py, и запустите командой python crawl.py.

Шаг 3. Передайте прокси в CrawlerRunConfig

Создайте ProxyConfig с адресом http://gw.prokso.com:823 и отдельными полями username и password и передайте его параметром proxy_config в CrawlerRunConfig. Именно так советует официальная документация: прокси задаётся для каждого запуска arun, а параметр прокси в BrowserConfig там помечен как устаревший.

Шаг 4. Логин, пароль и страна

Логин и пароль возьмите из генератора в кабинете. Отдельные поля username и password удобнее адреса с паролем: спецсимволы не нужно кодировать. Страну задаёт логин: ЛОГИН__cr.de — страницы будут открываться с немецких адресов. Для браузера берите схему http://: логин и пароль Chromium передаёт только HTTP-прокси.

Шаг 5. Выберите порт под задачу

Порт 823 даёт новый IP на каждый запрос — он подходит для разового сбора отдельных страниц. Если краулер проходит несколько страниц одного сайта в одной сессии (вход в аккаунт, корзина, пагинация), возьмите фиксированный порт 10000–20000: сайт связывает сессию с IP, и смена адреса посреди неё выглядит подозрительно. Адрес на порту держится от 1 до 120 минут, время настраивается в кабинете.

import asyncio
from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, ProxyConfig


def sticky(port):
    return CrawlerRunConfig(proxy_config=ProxyConfig(
        server=f"http://gw.prokso.com:{port}",
        username="ЛОГИН",
        password="ПАРОЛЬ",
    ))


async def main():
    async with AsyncWebCrawler(config=BrowserConfig()) as crawler:
        for port in (10001, 10002):
            config = sticky(port)
            for _ in range(2):
                result = await crawler.arun(url="https://api.ipify.org", config=config)
                print(port, result.markdown)


asyncio.run(main())

Сохраните код в файл, например crawl.py, и запустите командой python crawl.py.

Шаг 6. Несколько сессий — свой порт на каждую

Поскольку прокси живёт в CrawlerRunConfig, для каждой сессии можно собрать отдельную конфигурацию со своим фиксированным портом. В примере два порта: запросы через один порт возвращают тот же IP, через разные — разные адреса.

Шаг 7. Проверьте вывод

Запустите пример: краулер открывает https://api.ipify.org и печатает IP, который видит сайт. Это должен быть адрес прокси, а не ваш. Ошибка 407 означает неверный логин или пароль либо закончившийся трафик на плане. Страница «Мой IP» в вашем браузере здесь не поможет: скрипт запускает собственный браузер, а ваш идёт напрямую.

arun_many и фиксированный порт на каждый воркер

arun_many() берёт весь список адресов и открывает страницы параллельно через диспетчер. Прокси живёт в CrawlerRunConfig, поэтому с одной конфигурацией все страницы идут через один прокси: на порту 823 каждая получает новый IP. Если страницы должны идти с фиксированного набора адресов, разделите список и дайте каждой части свой фиксированный порт.

import asyncio
import os
from crawl4ai import (AsyncWebCrawler, BrowserConfig, CacheMode, CrawlerRunConfig,
                      MemoryAdaptiveDispatcher, ProxyConfig, RateLimiter)

PASSWORD = os.environ["PROKSO_PASSWORD"]  # пароль не храним в коде

URLS = [f"https://example.de/catalog?page={n}" for n in range(1, 31)]
PORTS = [10001, 10002, 10003]  # один фиксированный порт = один IP на воркер


def config_for(port):
    return CrawlerRunConfig(
        proxy_config=ProxyConfig(
            server=f"http://gw.prokso.com:{port}",
            username="ЛОГИН__cr.de",
            password=PASSWORD,
        ),
        cache_mode=CacheMode.ENABLED,  # не загружать повторно то, что уже есть в кэше
        page_timeout=90000,  # миллисекунды
    )


async def worker(crawler, port, urls):
    dispatcher = MemoryAdaptiveDispatcher(
        max_session_permit=2,
        rate_limiter=RateLimiter(base_delay=(2.0, 5.0), max_retries=2),
    )
    results = await crawler.arun_many(urls=urls, config=config_for(port), dispatcher=dispatcher)
    for r in results:
        print(port, r.url, r.status_code if r.success else r.error_message)


async def main():
    browser = BrowserConfig(text_mode=True)  # без картинок, шрифтов и медиа
    async with AsyncWebCrawler(config=browser) as crawler:
        parts = [URLS[i::len(PORTS)] for i in range(len(PORTS))]
        await asyncio.gather(*(worker(crawler, p, part) for p, part in zip(PORTS, parts)))


asyncio.run(main())

MemoryAdaptiveDispatcher с max_session_permit=2 держит открытыми не больше двух страниц на воркер, а RateLimiter добавляет случайную паузу 2–5 секунд между запросами к одному домену. page_timeout задаётся в миллисекундах, по умолчанию 60000: через резидентские адреса страницы грузятся медленнее, чем напрямую, так что 90 секунд — разумный запас. Время удержания IP в кабинете поставьте дольше, чем занимает часть списка одного воркера.

Как читать error_message в Crawl4AI: коды net::ERR и тайм-ауты

Crawl4AI не бросает исключение на неудачной странице: result.success равен False, а причина — в result.error_message, после «Failed on navigating ACS-GOTO». Самые частые причины через прокси:

  • net::ERR_PROXY_CONNECTION_FAILED. Chromium не смог подключиться к прокси: неверный хост или порт в server, либо исходящие соединения на этот порт заблокированы на вашей машине или в контейнере.
  • net::ERR_TUNNEL_CONNECTION_FAILED. Прокси доступен, но не открыл туннель к сайту. Проверьте, что на плане есть трафик и он не на паузе, что сайта нет в списке закрытых сайтов и что он работает на открытом порту, например 80, 443, 8080 или 8443.
  • Timeout 60000ms exceeded. Страница не загрузилась за page_timeout. Увеличьте его и оставьте wait_until="domcontentloaded" (значение по умолчанию): ожидание networkidle на страницах с бесконечными фоновыми запросами часто заканчивается тайм-аутом.
  • success равен True, но status_code — 403 или 429. Сайт ответил, но отказывает. RateLimiter по умолчанию реагирует на 429 и 503: удваивает паузу для этого домена и останавливается после max_retries таких ответов подряд. На 403 замедлитесь сами и проверьте правила сайта.

Экономия трафика в Crawl4AI: кэш, text_mode и robots.txt

Браузер загружает всё, что просит страница, а трафик считается в обе стороны. В версии 0.9.5 CrawlerRunConfig по умолчанию не читает кэш, так что каждый запуск загружает страницы заново. CacheMode.ENABLED читает и пишет локальный кэш, и повторный запуск берёт уже имеющиеся страницы с диска.

BrowserConfig(text_mode=True) блокирует картинки, шрифты и медиафайлы и выключает JavaScript. Трафика становится заметно меньше, но страницы, которые строят содержимое на JavaScript, вернутся пустыми: для них оставьте text_mode выключенным и используйте avoid_css=True. Обратите внимание: exclude_all_images и exclude_external_images только чистят результат, а картинки всё равно загружаются.

check_robots_txt=True заставляет краулер читать robots.txt и пропускать запрещённые страницы с сообщением «Access denied by robots.txt». Это простой способ держать сбор в рамках правил сайта и наших правил использования.

Если прокси не работает

Вопросы и ответы

Для какой версии написана инструкция?

Для версии Crawl4AI 0.9.5. В ней прокси передают через CrawlerRunConfig(proxy_config=…). Старый параметр proxy в BrowserConfig ещё работает, но печатает предупреждение об устаревании и будет убран.

Можно ли взять прокси из переменной окружения?

Да. ProxyConfig.from_env() читает переменную PROXIES со списком через запятую в формате хост:порт:логин:пароль, например gw.prokso.com:823:ЛОГИН:ПАРОЛЬ. Так пароль не попадает в код.

Что значит ошибка 407?

Прокси не принял логин или пароль. Скопируйте их из генератора в кабинете ещё раз, без пробелов в начале и в конце, и проверьте, остался ли трафик на плане.

Можно ли дать arun_many список прокси вместо деления адресов?

proxy_config принимает и список ProxyConfig, но это упорядоченный список для попыток по очереди, а не распределение адресов между IP. Чтобы привязать часть списка к одному IP, запускайте отдельный arun_many() со своим портом, как в примере.

Почему с text_mode получается пустой markdown?

text_mode выключает JavaScript в браузере. Если сайт рисует содержимое скриптами, конвертировать нечего. Для таких сайтов выключите text_mode и экономьте трафик кэшем и avoid_css.