Актуализирован README и очищены служебные артефакты
Some checks failed
CI/CD Pipeline / Code Quality Checks (push) Successful in 1m58s
CI/CD Pipeline / Run Tests (push) Failing after 2m2s
CI/CD Pipeline / Build & Push Images (push) Has been skipped

- Полностью обновлена документация проекта под текущую архитектуру

- Добавлены исчерпывающие инструкции локального запуска: Docker и без Docker

- Уточнены реальные API эндпоинты, задачи Celery, переменные окружения и prod/dev сценарии

- Удалены вспомогательные временные файлы: concatenate_files.py и один_файл.docx
This commit is contained in:
2026-02-18 13:30:31 +01:00
parent d5d184537f
commit ff7884ebe9
3 changed files with 228 additions and 415 deletions

528
README.md
View File

@@ -1,349 +1,277 @@
# Django ETL Boilerplate
# Mostovik Backend
Шаблон Django приложения для ETL (Extract, Transform, Load) операций с функциями веб-скрапинга.
Backend-сервис на Django/DRF для сбора, хранения и выдачи данных из государственных источников (Минпромторг, ЕРП, ЕИС закупок, ФНС), с асинхронной обработкой через Celery.
## Технологический стек
## Что умеет проект
- **Python**: 3.11.2
- **Django**: 3.2.25
- **Django REST Framework**: 3.14.0
- **PostgreSQL**: 15.10
- **Redis**: 7.x
- **Celery**: 5.3.6
- **Playwright**: 1.52+ (browser automation)
- **Gunicorn**: 21.2.0
- **Apache**: 2.4.57
- JWT-аутентификация и профиль пользователя.
- Swagger UI документация API.
- Health/Liveness/Readiness эндпоинты.
- Фоновые задачи с трекингом статуса (`BackgroundJob`).
- Парсеры источников:
- Минпромторг: сертификаты и реестр производителей.
- Единый реестр проверок (`proverki.gov.ru`, включая 248-ФЗ/294-ФЗ).
- Закупки (`zakupki.gov.ru`, SOAP API с токеном).
- ФНС: загрузка и обработка Excel-отчётности (`fin_{id}_{ogrn}.xlsx`).
- Админ-панель на Jazzmin для мониторинга данных и логов загрузок.
## Парсеры данных
## Технологии
Проект включает парсеры для загрузки данных из государственных источников:
### Минпромторг (minpromtorg.gov.ru)
- **Сертификаты промышленного производства** - `parse_industrial_production`
- **Реестр производителей** - `parse_manufactures`
### Единый реестр проверок (proverki.gov.ru)
- **Проверки по ФЗ-294** - традиционные проверки
- **Проверки по ФЗ-248** - новые проверки с 2021 года
- **Автоматическая синхронизация** - `sync_inspections`
### Запуск парсеров
```python
# Через Celery
from apps.parsers.tasks import (
parse_industrial_production,
parse_manufactures,
parse_inspections,
sync_inspections,
)
# Парсинг сертификатов
parse_industrial_production.delay()
# Парсинг производителей
parse_manufactures.delay()
# Парсинг проверок за конкретный месяц
parse_inspections.delay(year=2025, month=10, is_federal_law_248=False)
# Автоматическая синхронизация (с 01.01.2025 до текущего месяца)
sync_inspections.delay()
```
### Особенности парсера proverki.gov.ru
- Использует **Playwright** для JS-рендеринга
- Поддержка **потокового парсинга** для больших файлов (>50 МБ)
- Автоматическое определение последнего загруженного периода
- Раздельная загрузка ФЗ-294 и ФЗ-248
- Python 3.11
- Django 3.2
- Django REST Framework
- PostgreSQL 15
- Redis 7
- Celery + django-celery-beat + django-celery-results
- drf-yasg (Swagger/OpenAPI)
- uv (управление зависимостями)
- Docker / Docker Compose
## Структура проекта
```
mostovik-backend/
├── src/ # Исходный код Django
│ ├── apps/ # Django приложения
│ │ ── user/ # Приложение пользователей
│ ├── core/ # Runtime-конфигурация проекта (urls/asgi/wsgi/celery)
├── settings/ # Django settings (base, dev, production, test)
── manage.py # Управление Django
├── tests/ # Тесты (в корне проекта)
── apps/user/ # Тесты для user app
│ ├── conftest.py # Конфигурация pytest
│ └── README.md # Документация по тестам
├── docker/ # Docker конфигурации
├── pyproject.toml # Конфигурация проекта и инструментов
├── Makefile # Команды для разработки
├── docker-compose.dev.yml # Docker Compose для разработки
── docker-compose.prod.yml # Docker Compose для production
```text
.
├── src/
│ ├── apps/
│ │ ── core/ # health, background jobs, openapi, startup checks
│ ├── user/ # auth, профиль пользователя
│ └── parsers/ # клиенты/сервисы/задачи парсеров
── core/ # urls/asgi/wsgi/celery
│ ├── settings/ # base/dev/production/test
── manage.py
├── tests/
├── docker/
│ ├── Dockerfile
│ └── scripts/
├── input/ # входящие/обработанные/ошибочные файлы ФНС
├── docker-compose.dev.yml
── docker-compose.prod.yml
└── Makefile
```
## Быстрый старт (локальная разработка)
## Переменные окружения
### 1. Установка зависимостей
Ключевые переменные:
- `DJANGO_SETTINGS_MODULE`: `settings.dev` (локально/dev) или `settings.production` (prod).
- `POSTGRES_*`: доступ к PostgreSQL.
- `REDIS_CACHE_URL`, `CELERY_BROKER_URL`, `CELERY_RESULT_BACKEND`: Redis/Celery.
- `CHECKO_API_KEY`: ключ API Checko.
- `ZAKUPKI_TOKEN`: токен SOAP API ЕИС закупок.
- `COLLECTSTATIC_ON_MIGRATE`: `1`/`0`.
- `STARTUP_CHECKS_ENABLED`: fail-fast проверки DB/Redis перед стартом runtime-процессов.
Важно: если используете `.env.dev`/`.env.prod`, проверьте, что `DJANGO_SETTINGS_MODULE` указывает на `settings.*`, а не на устаревший `config.settings.*`.
## Локальный запуск в Docker (рекомендуется)
### 1. Подготовка
```bash
# Установка uv (если не установлен)
curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.cargo/env
# Создание виртуального окружения с uv
uv venv .venv
source .venv/bin/activate
# Установка зависимостей через uv
uv pip install -e ".[dev]"
# Или через Makefile
make install
# Настройка окружения разработки (pre-commit hooks)
make setup-dev
# из корня проекта
cp .env.prod.example .env.prod # только если нужен prod compose
```
### 2. Настройка окружения
Для dev используется `.env.dev`. При необходимости поправьте:
```bash
# Для dev compose уже готов файл .env.dev (можно использовать как есть).
# Для prod compose заполните .env.prod на основе .env.prod.example.
```env
DJANGO_SETTINGS_MODULE=settings.dev
```
### 3. Запуск с Docker Compose (рекомендуется)
### 2. Старт dev-стека
```bash
# Запуск всех dev сервисов (db, redis, migrate, web, celery)
make dev-up
# или:
docker compose -f docker-compose.dev.yml up -d
```
# Проверка состояния контейнеров
Сервисы:
- `db` (PostgreSQL)
- `redis`
- `migrate` (однократный запуск миграций)
- `web` (Django runserver)
- `celery_worker`
- `celery_beat`
### 3. Проверка
```bash
docker compose -f docker-compose.dev.yml ps
# Просмотр логов
docker compose -f docker-compose.dev.yml logs -f web
```
### 4. Ручная настройка (без Docker)
### 4. Остановка
#### Запуск баз данных:
```bash
# PostgreSQL
sudo systemctl start postgresql
# Redis
sudo systemctl start redis
make dev-down
```
#### Миграции и запуск:
## Локальный запуск без Docker
Вариант для разработки на хосте.
### 1. Зависимости
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
source "$HOME/.cargo/env"
uv sync --dev
```
### 2. Поднять PostgreSQL и Redis
Любым удобным способом (локально через сервисы или контейнеры). Пример с Docker:
```bash
docker run -d --name mostovik_pg \
-e POSTGRES_DB=mostovik \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=postgres \
-p 5432:5432 postgres:15.10
docker run -d --name mostovik_redis -p 6379:6379 redis:7-alpine
```
### 3. Экспорт переменных
```bash
export DJANGO_SETTINGS_MODULE=settings.dev
export POSTGRES_HOST=127.0.0.1
export POSTGRES_PORT=5432
export POSTGRES_DB=mostovik
export POSTGRES_USER=postgres
export POSTGRES_PASSWORD=postgres
export REDIS_HOST=127.0.0.1
export REDIS_CACHE_URL=redis://127.0.0.1:6379/1
export CELERY_BROKER_URL=redis://127.0.0.1:6379/0
export CELERY_RESULT_BACKEND=redis://127.0.0.1:6379/0
```
### 4. Миграции и запуск
```bash
cd src
# Миграции
python manage.py makemigrations
python manage.py migrate
# Создание суперпользователя
python manage.py createsuperuser
# Запуск разработческого сервера
python manage.py runserver
# Запуск Celery worker (в отдельном терминале)
celery -A core worker --loglevel=info
# Запуск Celery beat (в отдельном терминале)
celery -A core beat --loglevel=info
uv run python manage.py migrate
uv run python manage.py createsuperuser
uv run python manage.py runserver
```
## API Endpoints
Основной префикс: `/api/`
### Data Processor
- `GET/POST /api/data-sources/` - Источники данных
- `GET/POST /api/data-pipelines/` - ETL пайплайны
- `GET /api/extracted-data/` - Извлеченные данные
- `GET /api/processing-logs/` - Логи обработки
### Web Scraping
- `GET/POST /api/scraping-jobs/` - Задачи скрапинга
- `GET /api/scraped-items/` - Скрапленные данные
- `GET/POST /api/spider-configurations/` - Конфигурации пауков
- `GET/POST /api/proxy-servers/` - Прокси сервера
### Аутентификация
- `POST /api/api-token-auth/` - Получение API токена
## Развертывание
Используется `docker-compose.prod.yml` и файл окружения `.env.prod`.
В отдельных терминалах:
```bash
# 1) Заполнить .env.prod (можно взять шаблон .env.prod.example)
cd src && DJANGO_SETTINGS_MODULE=settings.dev uv run celery -A core worker --loglevel=INFO
cd src && DJANGO_SETTINGS_MODULE=settings.dev uv run celery -A core beat --loglevel=INFO
```
Опционально для `proverki.gov.ru` fallback-режима:
```bash
uv run playwright install chromium
```
## API и доступные эндпоинты
Базовый URL в dev: `http://localhost:8000`
- Swagger UI: `GET /`
- Admin: `GET /admin/`
- Health: `GET /health/`, `GET /health/live/`, `GET /health/ready/`
Версионированный API: `/api/v1/`
- Пользователи и auth: `/api/v1/users/`
- Фоновые задачи: `/api/v1/jobs/`
- Минпромторг: `/api/v1/minpromtorg/`
- Проверки: `/api/v1/proverki/`
- Закупки: `/api/v1/zakupki/`
- ФНС: `/api/v1/fns/`
- Системные (admin): `/api/v1/system/`
Основные auth-эндпоинты:
- `POST /api/v1/users/register/`
- `POST /api/v1/users/login/`
- `POST /api/v1/users/token/refresh/`
- `POST /api/v1/users/token/verify/`
- `GET /api/v1/users/me/`
ФНС загрузка:
- `POST /api/v1/fns/upload/` (`multipart/form-data`, поле `files`)
- `GET /api/v1/fns/reports/`
- `GET /api/v1/fns/reports/{id}/`
## Парсеры и фоновые задачи
Celery-задачи (основные):
- `apps.parsers.tasks.parse_industrial_production`
- `apps.parsers.tasks.parse_manufactures`
- `apps.parsers.tasks.parse_inspections`
- `apps.parsers.tasks.sync_inspections`
- `apps.parsers.tasks.parse_procurements`
- `apps.parsers.tasks.sync_procurements`
- `apps.parsers.tasks.process_fns_file`
- `apps.parsers.tasks.scan_fns_directory`
Планировщик (`celery beat`) по умолчанию:
- ежедневный парсинг Минпромторга (сертификаты/производители)
- сканирование директории ФНС каждые 5 минут
Директории ФНС:
- входящие: `input/fns/`
- успешные: `input/fns/processed/`
- ошибки: `input/fns/failed/`
## Команды разработки
```bash
make install
make setup-dev
make test
make test-cov
make test-fast
make lint
make pre-commit
make pre-push
make migrate
make createsuperuser
make shell
```
## Production (docker-compose.prod.yml)
```bash
cp .env.prod.example .env.prod
# обязательно проверить:
# DJANGO_SETTINGS_MODULE=settings.production
# 2) Собрать и запустить сервисы
docker compose -f docker-compose.prod.yml --env-file .env.prod up -d --build
# 3) Проверить состояние
docker compose -f docker-compose.prod.yml --env-file .env.prod ps
```
## Мониторинг и логирование
В prod compose поднимаются:
### Логи приложения
```bash
# Логи Django
tail -f logs/django.log
- `migrate`
- `web` (gunicorn)
- `celery_worker`
- `celery_beat`
# Логи Celery
tail -f logs/celery.log
БД/Redis в prod compose не создаются, предполагаются внешние сервисы.
# Системные логи
journalctl -u gunicorn -f
journalctl -u celery-worker -f
```
## Наблюдаемость и диагностика
### Мониторинг Celery
```bash
# Запуск Flower (в отдельном терминале)
celery -A core flower
# Доступ через браузер: http://localhost:5555
```
## Разработка
### Запуск тестов
```bash
# Запуск всех тестов
make test
# Запуск с покрытием
make test-cov
# Запуск только быстрых тестов
make test-fast
# Запуск тестов конкретного модуля
make test TARGET=user
# Линтинг и форматирование
make lint
make format
# Проверка типов
make type-check
# Проверка безопасности
make security-check
```
### Создание миграций
```bash
# Через Makefile
make migrate
# Или напрямую
cd src
python manage.py makemigrations
python manage.py migrate
# Создание суперпользователя
make createsuperuser
```
### Работа с задачами Celery
```python
# В коде Python
from apps.data_processor.tasks import process_extracted_data
from apps.scraping.tasks import run_scraping_job
# Запуск асинхронно
result = process_extracted_data.delay()
print(result.id) # ID задачи
```
## Конфигурация инструментов
Все конфигурации инструментов разработки централизованы в файле `pyproject.toml`:
- **pytest**: настройки тестирования
- **coverage**: отчеты о покрытии кода
- **ruff**: линтинг и форматирование
- **black**: форматирование кода
- **isort**: сортировка импортов
- **mypy**: проверка типов
- **bandit**: проверка безопасности
### Полезные команды Make
- Health-checkи для оркестрации: `/health/live/`, `/health/ready/`, `/health/`.
- Расширенный health: `GET /health/?include_celery=true`.
- Логи контейнеров:
```bash
# Качество кода
make lint # Проверка линтерами
make format # Форматирование кода
make type-check # Проверка типов
make security-check # Проверка безопасности
make pre-commit # Запуск всех pre-commit hooks
# Тестирование
make test # Все тесты
make test-cov # Тесты с покрытием
make test-fast # Только быстрые тесты
# Разработка
make shell # Django shell
make migrate # Миграции
make clean # Очистка временных файлов
docker compose -f docker-compose.dev.yml logs -f web
docker compose -f docker-compose.dev.yml logs -f celery_worker
docker compose -f docker-compose.dev.yml logs -f celery_beat
```
## Безопасность
- Все секретные ключи хранятся в переменных окружения
- Используется HTTPS в продакшене
- Настроены заголовки безопасности в Apache
- Регулярное обновление зависимостей
## Поддержка
Для вопросов и поддержки обращайтесь к документации Django и используемым библиотекам:
- [Django Documentation](https://docs.djangoproject.com/)
- [Celery Documentation](https://docs.celeryproject.org/)
- [Scrapy Documentation](https://docs.scrapy.org/)
- [Django REST Framework](https://www.django-rest-framework.org/)
## Лицензия
MIT License
---
## Changelog
### 2026-01-21
#### Добавлено
- **Задача `sync_inspections`** - автоматическая синхронизация проверок с proverki.gov.ru
- Инкрементальная загрузка с последнего сохранённого периода
- Начало с 01.01.2025 если БД пуста
- Раздельная загрузка ФЗ-294 и ФЗ-248
- Автоматическая остановка при отсутствии данных (2 пустых месяца)
- **Поля в модели InspectionRecord**:
- `is_federal_law_248` - признак проверки по ФЗ-248
- `data_year` - год загруженных данных
- `data_month` - месяц загруженных данных
- **Потоковый парсинг XML** для файлов >50 МБ (iterparse)
- **Методы в InspectionService**:
- `get_last_loaded_period()` - получение последнего загруженного периода
- `has_data_for_period()` - проверка наличия данных за период
### 2026-01-20
#### Добавлено
- **Парсер proverki.gov.ru** с поддержкой Playwright
- Навигация по порталу (клик на вкладку "Скачать")
- Парсинг XML с namespaces
- Извлечение данных из атрибутов и вложенных элементов
### 2026-01-19
#### Добавлено
- **Парсеры Минпромторга** (сертификаты, производители)
- **Модуль apps.parsers** с клиентами, сервисами и задачами Celery
- **Django Admin** для управления записями парсеров
- Дедупликация по unique constraints

View File

@@ -1,115 +0,0 @@
"""
Скрипт для объединения всех файлов в дереве каталогов в один .docx файл.
Выходной файл будет содержать пути к файлам, за которыми следует их содержимое.
"""
import os
from pathlib import Path
from docx import Document
from docx.shared import Inches
import mimetypes
def is_binary_file(file_path):
"""
Проверяет, является ли файл двоичным, пытаясь прочитать его как текст.
"""
try:
with open(file_path, 'tr', encoding='utf-8') as check_file:
check_file.read(1024) # Читаем первые 1KB для проверки
return False
except UnicodeDecodeError:
return True
def should_skip_directory(directory):
"""
Определяет, нужно ли пропустить каталог на основе общих шаблонов игнорирования.
"""
skip_dirs = {'.git', '.venv', '__pycache__', 'node_modules', '.pytest_cache',
'data', '.idea', '.vscode', 'logs', 'media', 'staticfiles'}
return any(skip_dir in directory.parts for skip_dir in skip_dirs)
def should_skip_file(file_path):
"""
Определяет, нужно ли пропустить файл на основе расширений или шаблонов.
"""
skip_extensions = {'.jpg', '.jpeg', '.png', '.gif', '.bmp', '.ico', '.svg',
'.mp3', '.mp4', '.avi', '.mov', '.pdf', '.zip', '.tar',
'.gz', '.exe', '.so', '.dll', '.doc', '.docx', '.xls',
'.xlsx', '.ppt', '.pptx', '.db', '.sqlite', '.log'}
file_ext = Path(file_path).suffix.lower()
return file_ext in skip_extensions
def concatenate_files_to_docx():
"""
Основная функция для объединения всех текстовых файлов в один документ .docx.
Обрабатываем только файлы из директорий src/apps и src/config.
"""
print("Начинаем объединение файлов...")
# Создаем новый документ Word
doc = Document()
# Добавляем заголовок
doc.add_heading('Объединенные файлы', 0)
# Определяем целевые директории
target_dirs = [
Path('./src/apps'),
Path('./src/config')
]
# Проходим по файлам в целевых директориях
for target_dir in target_dirs:
if target_dir.exists():
for file_path in target_dir.rglob('*'):
if file_path.is_file():
# Пропускаем определенные типы файлов
if should_skip_file(file_path):
continue
# Пропускаем, если это двоичный файл
if is_binary_file(str(file_path)):
print(f"Пропускаем двоичный файл: {file_path}")
continue
try:
# Добавляем путь к файлу как заголовок
doc.add_heading(str(file_path), level=1)
# Читаем содержимое файла
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
# Удаляем пустые строки из содержимого
lines = [line for line in content.splitlines() if line.strip()]
clean_content = '\n'.join(lines)
# Добавляем содержимое в документ
if clean_content.strip(): # Добавляем только если есть содержимое
doc.add_paragraph(clean_content)
else:
doc.add_paragraph("[Пустой файл]")
print(f"Добавлен файл: {file_path}")
except Exception as e:
error_msg = f"Ошибка чтения файла {file_path}: {str(e)}"
print(error_msg)
doc.add_heading(f"ОШИБКА: {file_path}", level=1)
doc.add_paragraph(error_msg)
else:
print(f"Целевая директория не найдена: {target_dir}")
# Сохраняем документ
output_filename = "один_файл.docx"
doc.save(output_filename)
print(f"\nУспешно создан {output_filename} с объединенным содержимым!")
if __name__ == "__main__":
concatenate_files_to_docx()

Binary file not shown.