# OpenLane Scraper Парсер автомобилей с [OpenLane marketplace](https://app.openlane.com). Забирает данные через 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) ### Быстрый старт ```bash git clone cd openlane_scraper_project pip install -e . playwright install chromium cp .env.example .env # Заполнить OPENLANE_USERNAME, OPENLANE_PASSWORD в .env alembic upgrade head ``` ### Запуск ```bash # Терминал 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: ```bash openlane scrape-openlane --limit 20 ``` ## Docker ```bash 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) ```bash 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` — история запусков ## Структура ```text 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`). ```bash alembic upgrade head alembic revision --autogenerate -m "add_column_x" ``` ## Тесты ```bash pytest -q ``` Тесты работают на SQLite in-memory, без внешних зависимостей. ## Runtime-фильтры Файл `runtime_config.json` управляет runtime-поведением sync и фильтрацией автомобилей.