add project setup

This commit is contained in:
qananasikq
2026-04-21 23:48:20 +03:00
commit 6b55c8cb28
11 changed files with 1792 additions and 0 deletions

152
README.md Normal file
View File

@@ -0,0 +1,152 @@
# 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 25s между запросами, jitter 0120s перед стартом, circuit breaker (2 ошибки подряд → стоп), 403→немедленный стоп, 429→backoff×3.
- **Anti-detection**: блокировка ресурсов (bugsnag, intercom, pusher, analytics), stealth patches.
## Локальный запуск
### Требования
- **Python 3.11+**
- **PostgreSQL** и **Redis** (для Celery)
### Быстрый старт
```bash
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
```
### Запуск
```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 и фильтрацией автомобилей.