OpenLane Scraper
Парсер автомобилей с OpenLane marketplace. Забирает данные через API (GET /api/v4/search), сохраняет в PostgreSQL. Работает через Playwright (для авторизации), FastAPI, Celery и Docker.
Архитектура
- Авторизация: Okta OAuth2 PKCE через
okta.iam.karglobal.com. Сессия сохраняется вstorage_state.jsonи переиспользуется между запусками. - Сбор данных: API-запросы с заголовками
x-rbz-user-id,x-rbz-dealership-id(извлекаются из JWT access_token). - Защита аккаунта: throttle 2–5s между запросами, jitter 0–120s перед стартом, circuit breaker (2 ошибки подряд → стоп), 403→немедленный стоп, 429→backoff×3.
- Anti-detection: блокировка ресурсов (bugsnag, intercom, pusher, analytics), stealth patches.
Локальный запуск
Требования
- Python 3.11+
- PostgreSQL и Redis (для Celery)
Быстрый старт
git clone <repo-url>
cd openlane_scraper_project
pip install -e .
playwright install chromium
cp .env.example .env
# Заполнить OPENLANE_USERNAME, OPENLANE_PASSWORD в .env
alembic upgrade head
Запуск
# Терминал 1 — API
uvicorn openlane_scraper.api.app:app --reload --port 8000
# Терминал 2 — Celery Worker
celery -A openlane_scraper.worker.celery_app worker --loglevel=info --concurrency=1 --pool=solo -Q scraping
# Терминал 3 — Celery Beat (каждый час)
celery -A openlane_scraper.worker.celery_app beat --loglevel=info
CLI:
openlane scrape-openlane --limit 20
Docker
cp .env.example .env
docker compose up -d
Сервисы: postgres, redis, migrate, api, worker, beat.
beatзапускает сбор раз в 1 час (CELERY_BEAT_SYNC_INTERVAL_MINUTES=60)- Лимит по умолчанию: 20 машин (
OPENLANE_MAX_CARS_LIMIT=20)
API (Docker): http://localhost:58000 · Swagger: http://localhost:58000/docs
Первый логин (storage state)
docker compose run --rm --service-ports openlane-auth openlane openlane-login
# Войти вручную в браузере — storage state сохранится в volume
API
GET /health— статус сервисаGET /api/v1/stats— статистика (машины, картинки, топ брендов)GET /api/v1/cars— список с пагинациейGET /api/v1/cars/{id}— карточка с картинкамиPOST /api/v1/tasks/sync-listing— запустить сборGET /api/v1/sync-runs— история запусков
Структура
openlane_scraper/
scraper.py — оркестратор: circuit breaker, batched upsert, early-stop
cli.py — CLI-команды (scrape-openlane, openlane-login)
browser/
factory.py — создание браузера, stealth-инъекции, resource blocking
openlane/
auth.py — авторизация через storage_state / Okta PKCE
client.py — запросы к /api/v4/search с JWT-заголовками
checkpoint.py — checkpoint/resume по страницам
writer.py — JSONL + aggregated JSON
runner.py — orchestration, retry/backoff, progress
storage/
models.py — SQLAlchemy: Car, Image, SyncRun
schemas.py — Pydantic: CarRecord, ImageRecord, CarRead
enums.py — enum-значения (drive, gearbox, body_type, ...)
db.py — PersistenceService: upsert, sync runs, статистика
api/
app.py — FastAPI factory
deps.py — dependency injection
routes/ — health, cars, tasks
worker/
celery_app.py — конфиг Celery, beat-расписание
tasks.py — sync_listing_task с jitter и lock
core/
config.py — Settings (dataclass), env-переменные
logs.py — логирование с trace_id
retry.py — @retryable с exponential backoff
runtime_config.py — runtime-конфиг
utils.py — утилиты
Конфигурация
Всё через env-переменные (полный список в .env.example):
- OpenLane:
OPENLANE_USERNAME,OPENLANE_PASSWORD,OPENLANE_MAX_CARS_LIMIT - БД:
OPENLANE_DATABASE_URL,OPENLANE_DATABASE_POOL_SIZE - Redis:
OPENLANE_REDIS_URL - Celery:
CELERY_BROKER_URL,CELERY_BEAT_SYNC_INTERVAL_MINUTES - Прокси:
OPENLANE_PROXY_SERVER,OPENLANE_PROXY_USERNAME,OPENLANE_PROXY_PASSWORD
Миграции
В Docker миграции выполняются сервисом migrate (alembic upgrade head).
alembic upgrade head
alembic revision --autogenerate -m "add_column_x"
Тесты
pytest -q
Тесты работают на SQLite in-memory, без внешних зависимостей.
Runtime-фильтры
Файл runtime_config.json управляет runtime-поведением sync и фильтрацией автомобилей.
Description
Languages
Python
99.2%
Dockerfile
0.5%
Mako
0.3%