IAAI Scraper
Парсер аукционных автомобилей с iaai.com. Ходит по листингу, собирает карточки машин, вытаскивает данные из DOM и перехваченных XHR-ответов, складывает всё в PostgreSQL. Работает через Playwright (headless Chromium), крутится в Docker.
Как устроен сайт и его защита
У IAAI стоит Imperva Incapsula — внешний WAF и anti-bot.
- Anti-bot — headless Chromium без прокси часто режется.
- Динамическая подгрузка — часть данных приходит через XHR (
/Search,/VehicleDetail), часть есть в HTML. - Cookie consent — при первом заходе показывают баннер.
Поэтому в проекте используется Playwright, паузы между действиями и прокси.
Запуск
cp .env.example .env # подправить под себя
docker compose up -d
Поднимутся 5 контейнеров: postgres, redis, api, worker, beat. API на http://localhost:8000.
По умолчанию beat запускает сбор листинга раз в 1 час и обрабатывает до 26 машин за запуск (CELERY_BEAT_SYNC_INTERVAL_MINUTES=60, CELERY_BEAT_SYNC_LIMIT=26).
Swagger-документация: http://localhost:8000/docs
API
Здоровье и статистика:
GET /health— статус сервиса и подключения к БДGET /api/v1/stats— сколько машин/картинок в базе, топ брендов
Машины:
GET /api/v1/cars— список с пагинациейGET /api/v1/cars/{id}— карточка с картинкамиGET /api/v1/cars/by-origin/{origin_id}— поиск по IAAI stock number
Задачи:
POST /api/v1/tasks/sync-vehicle— скрапнуть одну машину по URLPOST /api/v1/tasks/sync-listing— запустить полный обход листингаGET /api/v1/tasks/{task_id}— статус задачиGET /api/v1/tasks— все задачиGET /api/v1/sync-runs— история запусков
Пример — скрапнуть конкретную машину:
curl -X POST http://localhost:8000/api/v1/tasks/sync-vehicle
-H "Content-Type: application/json" \
-d '{"vehicle_url": "https://www.iaai.com/VehicleDetail/45089484~US"}'
CLI
Для отладки без API/Celery:
python main.py init-db
python main.py collect-listing --make Toyota
python main.py sync-vehicle "https://www.iaai.com/VehicleDetail/45089484~US"
python main.py sync-listing --limit 10
Структура
iaai_scraper/
scraper.py — оркестратор: связывает browser → parser → storage
cli.py — CLI-команды (init-db, sync-vehicle, sync-listing, ...)
proxy_bridge.py — HTTP→SOCKS5 мост (Chromium не умеет SOCKS5 с авторизацией)
browser/
factory.py — создание браузера, stealth-инъекции, fingerprint
listing.py — сбор ссылок на машины с листинга, пагинация
network.py — перехват XHR/fetch ответов через Playwright events
pace.py — рандомные паузы и движение мыши
parsing/
parser.py — VehicleParser: 3 канала (DOM + XHR JSON + embedded JSON)
mapper.py — CarMapper: нормализация → CarRecord, content hash
storage/
models.py — SQLAlchemy: Car (30+ полей), Image, SyncRun, ScrapeTask
schemas.py — Pydantic: CarRecord, ImageRecord, CarRead
enums.py — допустимые значения (drive, gearbox, body_type, ...)
db.py — PersistenceService: upsert (insert/update/skip), sync runs
api/
app.py — FastAPI factory, lifespan, роутеры
deps.py — dependency injection (Settings, PersistenceService)
routes/
health.py — GET /health
cars.py — CRUD по машинам + GET /stats
tasks.py — управление Celery-задачами + sync-runs
worker/
celery_app.py — конфиг Celery, beat-расписание
tasks.py — sync_vehicle_task, sync_listing_task
core/
config.py — Settings (dataclass), все env-переменные
logs.py — логирование с trace_id (ContextVar)
retry.py — декоратор @retryable с exponential backoff
utils.py — VIN_RE, deep_find_key, вспомогательные функции
alembic/ — миграции БД
tests/ — 30 тестов (SQLite in-memory)
Конфигурация
Всё через env-переменные (полный список в .env.example):
БД: IAAI_DATABASE_URL, IAAI_DATABASE_POOL_SIZE
Redis: IAAI_REDIS_URL
Celery: CELERY_BROKER_URL, CELERY_BEAT_SYNC_INTERVAL_MINUTES
Скрапер: IAAI_HEADLESS, IAAI_SYNC_ONLY_NEW, IAAI_MAX_PAGES_PER_RUN
Прокси: IAAI_PROXY_SERVER, IAAI_PROXY_USERNAME, IAAI_PROXY_PASSWORD
Паузы: IAAI_BETWEEN_VEHICLES_MIN_S, IAAI_AFTER_PAGE_CHANGE_MAX_S и т.д.
Миграции
В Docker миграции накатываются автоматически при старте API-контейнера (alembic upgrade head в entrypoint).
Вручную:
alembic upgrade head
alembic revision --autogenerate -m "add_column_x"
Тесты
pytest -q
30 тестов, SQLite in-memory, без внешних зависимостей.