auction-scrapper/README.md
Vakula Uladimir 12f005e335 init
2025-10-17 11:27:52 +03:00

16 KiB
Raw Blame History

Parser Zakupok (Парсер Закупок)

AdonisJS 6 приложение для автоматического парсинга аукционов с сайта icetrade.by. Система автоматически собирает данные каждые 6 часов, сохраняет в PostgreSQL и отправляет Telegram уведомления по ключевым словам.

Возможности

  • 🔄 Автоматический парсинг аукционов каждые 6 часов
  • 🔍 Поиск по ключевым словам (заголовок, описание, организация)
  • 📱 Telegram уведомления пользователям
  • 📊 Логирование всех операций парсинга
  • 🗄️ PostgreSQL база данных с полной историей
  • Пагинация и rate limiting для стабильности
  • 🔧 REST API для управления

Технологический стек

  • Framework: AdonisJS 6 (TypeScript)
  • Database: PostgreSQL + Lucid ORM
  • Scheduler: adonisjs-scheduler
  • HTML Parser: Cheerio
  • Validation: Zod
  • Telegram Bot: Grammy
  • Testing: Japa

Установка

Требования

  • Node.js >= 20.6
  • PostgreSQL >= 14
  • npm >= 9

Шаги установки

# 1. Клонировать репозиторий
git clone <repository-url>
cd parser-zakupok

# 2. Установить зависимости
npm install

# 3. Скопировать .env файл
cp .env.example .env

# 4. Настроить переменные окружения
nano .env  # или любой редактор

# 5. Запустить миграции
node ace migration:run

# 6. Запустить приложение
npm run dev

Настройка .env

# Сервер
PORT=3333
HOST=localhost
NODE_ENV=development
APP_KEY=<generate-with-node-ace-generate:key>

# База данных PostgreSQL
DB_HOST=127.0.0.1
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=your_password
DB_DATABASE=parser_zakupok

# Telegram Bot
TELEGRAM_BOT_TOKEN=your_bot_token_from_@BotFather

# Опционально
LOG_LEVEL=info

Команды запуска

Режим разработки

# Запуск с hot reload (рекомендуется)
npm run dev

# Альтернативный вариант
node ace serve --hmr

# С watch режимом
node ace serve --watch

Production режим

# 1. Собрать проект
npm run build

# 2. Запустить миграции
node ace migration:run --force

# 3. Запустить сервер
npm start
# или
node build/bin/server.js

Команды базы данных

Миграции

# Выполнить все pending миграции
node ace migration:run

# Откатить последний batch
node ace migration:rollback

# Откатить все миграции
node ace migration:rollback --batch=0

# Пересоздать базу (drop + migrate)
node ace migration:fresh

# Fresh + seed данные
node ace migration:fresh --seed

Создание новых сущностей

# Создать миграцию
node ace make:migration create_table_name
node ace make:migration add_column_to_table

# Создать модель
node ace make:model ModelName

# Создать модель + миграцию
node ace make:model ModelName -m

# Создать контроллер
node ace make:controller ControllerName

Database утилиты

# Открыть REPL с доступом к моделям
node ace repl

# Примеры в REPL:
# > await loadModels()
# > const Auction = await import('#models/auction')
# > await Auction.default.all()

Команды парсинга

Основная команда parse:auctions

# Парсинг с дефолтными настройками (до 10 страниц)
node ace parse:auctions

# Парсинг конкретного количества страниц
node ace parse:auctions --pages=5

# Парсинг без отправки уведомлений (только сохранение)
node ace parse:auctions --skip-notifications

# Парсинг 1 страницы без уведомлений (для тестирования)
node ace parse:auctions --pages=1 --skip-notifications

# Комбинация опций
node ace parse:auctions --pages=20 --skip-notifications

Что делает команда:

  1. Создает запись в parse_logs (статус: running)
  2. Парсит страницы с icetrade.by с rate limiting (1 сек между запросами)
  3. Валидирует данные через Zod схемы
  4. Upsert аукционов по auction_num (обновляет существующие, создает новые)
  5. Ищет совпадения по ключевым словам
  6. Создает записи уведомлений для пользователей
  7. Обновляет parse_log (статус: completed/failed, статистика)

Выводит:

  • Количество найденных аукционов
  • Количество новых аукционов
  • Количество обновленных аукционов
  • Количество созданных уведомлений
  • Время выполнения
  • Ошибки (если есть)

Команды Scheduler

Управление планировщиком

# Запустить scheduler (production)
node ace scheduler:work

# Запустить с watch режимом (development)
node ace scheduler:work --watch

# Показать список всех запланированных задач
node ace scheduler:list

# Вывод scheduler:list:
# ┌────────────────┬──────────────────┬─────────────────┐
# │ Name           │ Cron Expression  │ Next Run        │
# ├────────────────┼──────────────────┼─────────────────┤
# │ parse:auctions │ 0 0 */6 * * *    │ 2024-01-15 18:00│
# └────────────────┴──────────────────┴─────────────────┘

Настройка расписания

Расписание настроено в start/scheduler.ts:

// Текущее: каждые 6 часов (00:00, 06:00, 12:00, 18:00)
scheduler.call(async () => {
  await ace.exec('parse:auctions', [])
}).cron('0 0 */6 * * *')

// Другие варианты расписания:
// .cron('0 0 * * * *')      // Каждый час
// .cron('0 */30 * * * *')   // Каждые 30 минут
// .everyFourHours()         // Каждые 4 часа
// .dailyAt('09:00')         // Ежедневно в 9:00
// .twiceDaily(9, 18)        // Дважды в день (9:00, 18:00)

Production deployment scheduler

# Вариант 1: Использовать встроенный scheduler
npm start &  # Запустить сервер
node ace scheduler:work  # Запустить scheduler в отдельном процессе

# Вариант 2: Использовать PM2 (рекомендуется)
pm2 start ecosystem.config.js

# Вариант 3: Systemd services
# Создать два сервиса: parser-app.service и parser-scheduler.service

Команды тестирования

# Запустить все тесты
npm test
# или
node ace test

# Запустить конкретный файл теста
node ace test --files=tests/unit/models/auction.spec.ts

# Запустить тесты по паттерну (grep)
node ace test --grep="keyword matching"
node ace test --grep="scraper"

# Запустить только unit тесты
node ace test tests/unit

# Запустить только functional тесты
node ace test tests/functional

Code Quality команды

# Проверка типов TypeScript
npm run typecheck

# Линтинг (ESLint)
npm run lint

# Автофикс линтинга
npm run lint -- --fix

# Форматирование (Prettier)
npm run format

# Проверить форматирование без изменений
npm run format -- --check

Telegram Bot команды

# Запустить Telegram бота (когда будет реализовано в Phase 5)
node ace telegram:start

# С watch режимом
node ace telegram:start --watch

Команды бота для пользователей

После запуска бота, пользователи могут использовать:

  • /start - Регистрация в системе
  • /addkeyword <слово> - Добавить ключевое слово
  • /keywords или /listkeywords - Список ваших ключевых слов
  • /deletekeyword <id> - Удалить ключевое слово
  • /help - Справка по командам

Структура проекта

parser-zakupok/
├── app/
│   ├── controllers/       # HTTP контроллеры
│   ├── models/           # Lucid ORM модели
│   │   ├── auction.ts
│   │   ├── keyword.ts
│   │   ├── user.ts
│   │   ├── notification.ts
│   │   └── parse_log.ts
│   ├── services/         # Бизнес-логика
│   │   ├── scraper_service.ts       # Парсинг icetrade.by
│   │   └── notification_service.ts   # Обработка уведомлений
│   ├── middleware/       # HTTP middleware
│   └── validators/       # VineJS валидаторы
├── commands/             # Ace CLI команды
│   └── parse_auctions.ts # Команда парсинга
├── config/              # Конфигурация приложения
│   ├── app.ts
│   ├── database.ts
│   └── logger.ts
├── database/
│   └── migrations/      # Database миграции
├── start/
│   ├── routes.ts        # Маршруты
│   ├── kernel.ts        # Middleware регистрация
│   ├── scheduler.ts     # Настройка scheduler
│   └── env.ts           # Env validation
├── tests/               # Тесты (Japa)
│   ├── unit/
│   └── functional/
├── docs/                # Документация
├── .env                 # Environment переменные
├── adonisrc.ts         # AdonisJS конфигурация
└── package.json

Import Aliases

В проекте настроены удобные алиасы для импортов:

#controllers/*   ./app/controllers/*.js
#models/*        ./app/models/*.js
#services/*      ./app/services/*.js
#validators/*    ./app/validators/*.js
#middleware/*    ./app/middleware/*.js
#config/*        ./config/*.js
#database/*      ./database/*.js
#start/*         ./start/*.js

// Пример использования:
import Auction from '#models/auction'
import ScraperService from '#services/scraper_service'
import { DatabaseConfig } from '#config/database'

Логирование

Все операции логируются через Pino logger:

import logger from '@adonisjs/core/services/logger'

// В коде:
logger.info('Scraping started')
logger.error({ err }, 'Failed to parse page')
logger.debug({ count: auctions.length }, 'Auctions scraped')

Логи сохраняются в:

  • tmp/logs/app.log (production)
  • Console output (development)

Parse Logs в БД

Каждый запуск парсинга создает запись в таблице parse_logs:

SELECT * FROM parse_logs ORDER BY started_at DESC LIMIT 5;

-- Поля:
-- id, parse_type, status, started_at, completed_at,
-- items_found, items_new, items_updated, items_failed,
-- error_message, error_details

Полезные запросы:

-- Последние успешные парсинги
SELECT * FROM parse_logs
WHERE status = 'completed'
ORDER BY started_at DESC;

-- Статистика по парсингам
SELECT
  COUNT(*) as total_runs,
  AVG(items_found) as avg_found,
  AVG(items_new) as avg_new,
  SUM(items_failed) as total_failed
FROM parse_logs
WHERE parse_type = 'auction';

-- Неудачные парсинги с ошибками
SELECT started_at, error_message
FROM parse_logs
WHERE status = 'failed'
ORDER BY started_at DESC;

Troubleshooting

База данных не подключается

# Проверить что PostgreSQL запущен
# Linux/Mac:
sudo systemctl status postgresql

# Windows:
# Проверить через Services (services.msc)

# Проверить подключение
psql -U postgres -h localhost

# Создать базу вручную
psql -U postgres
CREATE DATABASE parser_zakupok;
\q

Ошибки при парсинге

# Проверить логи
tail -f tmp/logs/app.log

# Проверить parse_logs в БД
node ace repl
> await loadModels()
> const ParseLog = await import('#models/parse_log')
> await ParseLog.default.query().orderBy('started_at', 'desc').first()

# Запустить парсинг одной страницы для отладки
node ace parse:auctions --pages=1 --skip-notifications

Scheduler не запускается

# Проверить что scheduler провайдер добавлен в adonisrc.ts
cat adonisrc.ts | grep scheduler

# Проверить список задач
node ace scheduler:list

# Запустить вручную для проверки
node ace parse:auctions

TypeScript ошибки

# Очистить build и пересобрать
rm -rf build/
npm run build

# Проверить типы
npm run typecheck

# Обновить зависимости
npm update

API Endpoints (будут реализованы в Phase 7)

GET    /api/auctions          # Список аукционов (пагинация, фильтры)
GET    /api/auctions/:id      # Детали аукциона
GET    /api/keywords          # Ключевые слова пользователя
POST   /api/keywords          # Добавить ключевое слово
DELETE /api/keywords/:id      # Удалить ключевое слово
GET    /api/notifications     # История уведомлений

Docker (будет реализовано в Phase 8)

# Сборка и запуск
docker-compose up -d

# Просмотр логов
docker-compose logs -f app

# Остановка
docker-compose down

Roadmap

  • Phase 1: Project Setup
  • Phase 2: Database Models & Migrations
  • Phase 3: ScraperService Implementation
  • Phase 4: Scheduler Command
  • Phase 5: Telegram Bot Integration
  • Phase 6: NotificationService Enhancement
  • Phase 7: REST API Endpoints
  • Phase 8: Docker Deployment

Contributing

  1. Fork репозиторий
  2. Создать feature branch (git checkout -b feature/AmazingFeature)
  3. Commit изменения (git commit -m 'Add some AmazingFeature')
  4. Push в branch (git push origin feature/AmazingFeature)
  5. Открыть Pull Request

License

MIT License

Поддержка

При возникновении проблем:

  1. Проверьте документацию
  2. Создайте Issue
  3. Проверьте существующие Issues

Полезные ссылки