# IAAI Scraper Скрапер листинга автомобилей с сайта IAAI. Собирает данные карточек через Playwright, парсит HTML и перехваченные JSON ответы, нормализует и сохраняет в PostgreSQL или SQLite через SQLAlchemy. По умолчанию работает последовательно одна машина за раз, с паузами между запросами. JSON-результаты CLI по умолчанию сохраняются в `artifacts/json/`, чтобы не засорять корень проекта. ## Что делает 1. Открывает страницу листинга `Vehiclelisting/Cars`, собирает ссылки на карточки. 2. Переходит на каждую карточку, перехватывает XHR/fetch JSON-ответы. 3. Парсит DOM-текст, ``, встроенные `<script>` с JSON, сетевые payload'ы. 4. Маппит всё в единую структуру `CarRecord` (pydantic) с нормализацией полей. 5. Делает upsert в БД по `origin_id`, сравнивая `content_hash`, чтобы пропускать неизменившиеся записи. 6. Защищён от дублей: `origin_id` уникален, одинаковые записи пропускаются, а повторные картинки заменяются безопасно. ## Структура проекта ``` iaai_scraper/ ├── browser/ │ ├── factory.py # запуск Chrome/Chromium с desktop-фингерпринтом │ ├── network.py # перехват XHR/fetch, фильтрация и категоризация JSON │ └── pace.py # паузы между действиями ├── core/ │ ├── config.py # настройки из .env │ ├── logs.py # setup logging │ ├── retry.py # retry-декоратор │ └── utils.py # regex, deep_find_key, save_to_json ├── parsing/ │ ├── parser.py # DOM + JSON парсинг │ └── mapper.py # нормализация в CarRecord ├── storage/ │ ├── models.py # ORM: cars, images, sync_runs │ ├── schemas.py # pydantic-схемы │ ├── db.py # upsert с content_hash │ ├── listing.py # сбор ссылок из листинга │ └── enums.py # enum-значения для БД ├── scraper.py # главный модуль └── cli.py # CLI (argparse) ``` ## Установка ```bash pip install -r requirements.txt python -m playwright install chromium ``` ## Настройка Создайте `.env` на основе `.env.example`: ```env IAAI_HEADLESS=true IAAI_DATABASE_URL=postgresql+psycopg://postgres:postgres@localhost:5432/iaai_scraper ``` Все настройки (pacing, лимиты, gentle mode, retry/backoff, scheduler) задаются через переменные окружения в `.env.example`. ### БД для рабочего сайта Для рабочего запуска нужно **PostgreSQL**. Пример: ```env IAAI_DATABASE_URL=postgresql+psycopg://postgres:postgres@localhost:5432/iaai_scraper ``` SQLite подходит для локальной отладки, но не для production-сценария сайта. ### Scheduler по умолчанию Режим : - запуск раз в **1 час** - лимит **30 машин за цикл** - обрабатываются только **новые авто** (по умолчанию `IAAI_SYNC_ONLY_NEW=true`) Это уже отражено в актуальных env-настройках. ### Прокси и anti-bot IAAI использует anti-bot / fraud protection. Что важно: - предпочтительно использовать **USA residential** или **USA mobile** прокси - для Playwright лучше использовать **HTTP/HTTPS proxy** - Chromium **не поддерживает SOCKS5 с аутентификацией напрямую** - поэтому для production желательно покупать прокси, который отдаёт именно HTTP/HTTPS доступ Если используется встроенный bridge `iaai_scraper/proxy_bridge.py` (HTTP/HTTPS → SOCKS5), в нём добавлены базовые меры стабильности: - корректное чтение request body через `rfile` - поддержка `Transfer-Encoding: chunked` для request body - базовое логирование запросов и ошибок - таймауты relay-соединений - ограничение числа рабочих потоков (`PROXY_BRIDGE_MAX_WORKERS`) - безопасный ответ `502 Bad Gateway` без утечки внутренних исключений Пример: ```env IAAI_PROXY_SERVER=http://proxy.example.com:8080 IAAI_PROXY_USERNAME=username IAAI_PROXY_PASSWORD=password ``` ### Captcha / anti-bot detection В парсере добавлены признаки для определения возможной captcha / anti-bot страницы: - `possible_captcha` - `possible_antibot` - `dom_hints.has_captcha_text` - `dom_hints.has_antibot_text` Если сайт начнёт отдавать защитную страницу, это можно увидеть в результате scrape. ## Команды ```bash # создать таблицы python main.py init-db # собрать ссылки из листинга python main.py collect-listing --make Toyota --model Camry --output artifacts/json/listing.json # scrape одной карточки python main.py scrape-vehicle "https://www.iaai.com/VehicleDetail/41180634~US" --output artifacts/json/result.json # scrape + запись в БД python main.py sync-vehicle "https://www.iaai.com/VehicleDetail/41180634~US" --lane iaai # массовая синхронизация листинга python main.py sync-listing --make Toyota --model Camry --lane iaai_cars --limit 30 # при необходимости можно принудительно отключить фильтр only-new python main.py sync-listing --limit 30 --only-new false # daemon-режим (цикл каждые N минут) python main.py run-daemon --interval 60 ``` ## Тесты ```bash pytest tests -q ``` ## Docker ```bash # собрать образ docker compose build # запустить daemon (по умолчанию run-daemon) docker compose up -d # посмотреть логи docker compose logs -f # одноразовая команда docker compose run --rm iaai-scraper python main.py sync-listing --limit 5 # остановить (graceful shutdown) docker compose down ``` Контейнер автоматически перезапускается при крашах (`restart: unless-stopped`). Для Docker прокси также задаются через `.env`. ## Защита от дублей Система защищена от дублей на нескольких уровнях: - `origin_id` уникален в БД - при совпадении `content_hash` запись **пропускается** (`skipped`) - при обновлении запись не дублируется, а обновляется - изображения пересобираются без накопления дублей