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-20122013-20152016-20172018-20192020-20212022-20232024-20252026-2027
Если сегмент все равно слишком большой, discovery дополнительно режет его по id-диапазонам.
Стек
Python 3.11+PlaywrightFastAPICeleryRedisPostgreSQLSQLAlchemyAlembicDocker Compose
Быстрый старт через Docker
Это основной рекомендуемый способ запуска.
1. Подготовить окружение
cp .env.example .env
Если нужно, отредактируй .env.
2. Запустить стек
docker compose up -d
Поднимутся сервисы:
postgresredismigrateapiworkerbeat
3. Проверить статус
docker compose ps
API будет доступен по адресу:
http://localhost:18000- Swagger:
http://localhost:18000/docs
Порт пробрасывается как
${DUBIZZLE_API_HOST_PORT:-18000}:8000.
Полный сброс и чистый старт
Если нужен запуск с нуля с чистой БД и чистым Redis:
docker compose down -v --remove-orphans
docker compose up -d --build
Важно:
docker compose downне удаляет volumedocker 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
Отдельный сервис, который выполняет:
alembic upgrade head
api
Запускает:
uvicorn dubizzle_scraper.api.app:app --host 0.0.0.0 --port 8000
worker
Запускает Celery worker и выполняет scraping-задачи.
beat
Планировщик periodic tasks.
По умолчанию проект настроен на запуск каждые 60 минут.
Ручной запуск задач в Docker
Разовый sync listing
docker compose run --rm --profile manual sync
По умолчанию это запустит:
dubizzle sync-listing --limit 100 --output /app/artifacts/json/docker_sync_listing.json
Результат будет на хосте в:
artifacts/json/docker_sync_listing.json
Запуск с другим лимитом
docker compose run --rm --profile manual -e DUBIZZLE_SYNC_LISTING_LIMIT=500 sync
Запуск непрерывного режима
docker compose up -d api worker beat
Локальный запуск без Docker
Локальный запуск возможен, но проект в первую очередь ориентирован на PostgreSQL + Redis.
Установка
pip install -e .
playwright install chromium
Миграции
alembic upgrade head
Запуск API
uvicorn dubizzle_scraper.api.app:app --reload --port 8000
Запуск worker
celery -A dubizzle_scraper.worker.celery_app worker --loglevel=info --concurrency=1 --pool=solo -Q scraping
Запуск beat
celery -A dubizzle_scraper.worker.celery_app beat --loglevel=info
Полный sync листинга
dubizzle sync-listing --limit 100
Если включена сегментация и не переданы make, model, limit, CLI автоматически пойдет в segmented sync.
API
Базовые роуты:
Health
GET /health
Машины
GET /api/v1/carsGET /api/v1/cars/{car_id}GET /api/v1/cars/by-origin/{origin_id}GET /api/v1/stats
Задачи
POST /api/v1/tasks/sync-vehiclePOST /api/v1/tasks/sync-listingGET /api/v1/tasks/{task_id}GET /api/v1/sync-runs
Пример запуска sync vehicle
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
curl -X POST http://localhost:18000/api/v1/tasks/sync-listing \
-H "Content-Type: application/json" \
-d '{"limit": 100, "only_new": false}'
Тесты
pytest -q
Тесты покрывают:
- mapper
- parser
- listing
- scraper
- worker tasks
- resilience
- self-heal
- db