Files
dubizzle/README.md
2026-07-01 13:56:00 +03:00

296 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Dubizzle scraper
Сервис для сбора объявлений с `dubizzle.com`.
Основной сценарий работы:
- discovery списка машин через `Algolia`
- при необходимости fallback на сайт
- нормализация полей автомобиля
- upsert в PostgreSQL
- периодический запуск через `Celery Beat`
## Что делает проект
Проект:
- собирает все доступные машины из каталога `Dubizzle`
- использует `Algolia` как основной источник discovery
- обходит лимит одного запроса через сегментацию каталога
- сохраняет автомобили и изображения в PostgreSQL
- отдает API для просмотра данных и запуска задач
- поддерживает hourly/full scan через `Celery`
## Текущая архитектура
Сейчас проект настроен под `Dubizzle`.
Ключевые особенности:
- пакет проекта: `dubizzle_scraper`
- режим discovery по умолчанию: `algolia`
- full scan включен по умолчанию
- авто-сегментация: `DUBIZZLE_LISTING_SEGMENTS=auto`
- параллельный запуск сегментов: `CELERY_PARALLEL_SEGMENTS=true`
### Как собирается весь каталог
Один широкий запрос в `Algolia` упирается примерно в лимит $10{,}000$ доступных результатов. Поэтому проект использует сегментацию по годам.
Авто-сегменты (`auto`) сейчас разбивают каталог на 8 диапазонов по году:
- `1900-2012`
- `2013-2015`
- `2016-2017`
- `2018-2019`
- `2020-2021`
- `2022-2023`
- `2024-2025`
- `2026-2027`
Если сегмент все равно слишком большой, discovery дополнительно режет его по `id`-диапазонам.
## Стек
- `Python 3.11+`
- `Playwright`
- `FastAPI`
- `Celery`
- `Redis`
- `PostgreSQL`
- `SQLAlchemy`
- `Alembic`
- `Docker Compose`
## Быстрый старт через Docker
Это основной рекомендуемый способ запуска.
### 1. Подготовить окружение
```bash
cp .env.example .env
```
Если нужно, отредактируй `.env`.
### 2. Запустить стек
```bash
docker compose up -d
```
Поднимутся сервисы:
- `postgres`
- `redis`
- `migrate`
- `api`
- `worker`
- `beat`
### 3. Проверить статус
```bash
docker compose ps
```
API будет доступен по адресу:
- `http://localhost:18000`
- Swagger: `http://localhost:18000/docs`
> Порт пробрасывается как `${DUBIZZLE_API_HOST_PORT:-18000}:8000`.
## Полный сброс и чистый старт
Если нужен запуск с нуля с чистой БД и чистым Redis:
```bash
docker compose down -v --remove-orphans
docker compose up -d --build
```
Важно:
- `docker compose down` **не удаляет volume**
- `docker compose down -v` удаляет данные `PostgreSQL` и `Redis`
## Основные Docker-сервисы
### `postgres`
PostgreSQL база проекта.
По умолчанию:
- DB: `dubizzle_scraper`
- user: `dubizzle`
- password: `dubizzle`
- host port: `15432`
### `redis`
Используется как:
- broker для `Celery`
- backend для task state
- хранилище progress/state ключей
По умолчанию host port: `16379`
### `migrate`
Отдельный сервис, который выполняет:
```bash
alembic upgrade head
```
### `api`
Запускает:
```bash
uvicorn dubizzle_scraper.api.app:app --host 0.0.0.0 --port 8000
```
### `worker`
Запускает `Celery worker` и выполняет scraping-задачи.
### `beat`
Планировщик periodic tasks.
По умолчанию проект настроен на запуск каждые `60` минут.
## Ручной запуск задач в Docker
### Разовый sync listing
```bash
docker compose run --rm --profile manual sync
```
По умолчанию это запустит:
```bash
dubizzle sync-listing --limit 100 --output /app/artifacts/json/docker_sync_listing.json
```
Результат будет на хосте в:
- `artifacts/json/docker_sync_listing.json`
### Запуск с другим лимитом
```bash
docker compose run --rm --profile manual -e DUBIZZLE_SYNC_LISTING_LIMIT=500 sync
```
### Запуск непрерывного режима
```bash
docker compose up -d api worker beat
```
## Локальный запуск без Docker
Локальный запуск возможен, но проект в первую очередь ориентирован на `PostgreSQL + Redis`.
### Установка
```bash
pip install -e .
playwright install chromium
```
### Миграции
```bash
alembic upgrade head
```
### Запуск API
```bash
uvicorn dubizzle_scraper.api.app:app --reload --port 8000
```
### Запуск worker
```bash
celery -A dubizzle_scraper.worker.celery_app worker --loglevel=info --concurrency=1 --pool=solo -Q scraping
```
### Запуск beat
```bash
celery -A dubizzle_scraper.worker.celery_app beat --loglevel=info
```
### Полный sync листинга
```bash
dubizzle sync-listing --limit 100
```
Если включена сегментация и не переданы `make`, `model`, `limit`, CLI автоматически пойдет в segmented sync.
## API
Базовые роуты:
### Health
- `GET /health`
### Машины
- `GET /api/v1/cars`
- `GET /api/v1/cars/{car_id}`
- `GET /api/v1/cars/by-origin/{origin_id}`
- `GET /api/v1/stats`
### Задачи
- `POST /api/v1/tasks/sync-vehicle`
- `POST /api/v1/tasks/sync-listing`
- `GET /api/v1/tasks/{task_id}`
- `GET /api/v1/sync-runs`
### Пример запуска sync vehicle
```bash
curl -X POST http://localhost:18000/api/v1/tasks/sync-vehicle \
-H "Content-Type: application/json" \
-d '{"vehicle_url": "https://www.dubizzle.com/VehicleDetail/45089484~US"}'
```
### Пример запуска sync listing
```bash
curl -X POST http://localhost:18000/api/v1/tasks/sync-listing \
-H "Content-Type: application/json" \
-d '{"limit": 100, "only_new": false}'
```
## Тесты
```bash
pytest -q
```
Тесты покрывают:
- mapper
- parser
- listing
- scraper
- worker tasks
- resilience
- self-heal
- db