Refactor code structure and optimize performance across multiple modules
deploy / deploy (push) Has been cancelled
deploy / deploy (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,387 @@
|
||||
# RSS Parser для бизнес-новостей
|
||||
|
||||
Этот проект представляет собой многопарсерную систему для сбора бизнес-новостей с различных источников, разработанную на Spring Boot с сохранением данных в MongoDB.
|
||||
|
||||
## Описание
|
||||
|
||||
Система включает в себя два парсера:
|
||||
|
||||
- **Kursiv Media** (`https://kursiv.media/feed/`)
|
||||
- **Kapital.kz** (`https://kapital.kz/rss/`)
|
||||
|
||||
Оба парсера получают данные из RSS-лент, обрабатывают их и сохраняют в общую базу данных MongoDB с дедупликацией по хэшу.
|
||||
|
||||
**🔄 Автоматический режим работы:** Оба парсера автоматически запускаются каждые 30 минут (в 0 и 30 минут каждого часа) для обеспечения актуальности данных.
|
||||
|
||||
## Технологический стек
|
||||
|
||||
- **Java 21**
|
||||
- **Spring Boot 3.5.5**
|
||||
- **Spring Data MongoDB**
|
||||
- **Rome** - библиотека для парсинга RSS
|
||||
- **JSoup** - для очистки HTML
|
||||
- **MongoDB** - база данных
|
||||
|
||||
## Структура проекта
|
||||
|
||||
```
|
||||
src/main/java/kz/konturai/parser/
|
||||
├── ParserApplication.java # Главный класс приложения
|
||||
├── controller/
|
||||
│ └── ParserController.java # REST API контроллер
|
||||
├── model/
|
||||
│ └── MarketItem.java # Модель данных для MongoDB
|
||||
├── repository/
|
||||
│ └── MarketItemRepository.java # Репозиторий для работы с MongoDB
|
||||
└── service/
|
||||
└── KursivParserService.java # Основной сервис парсинга
|
||||
```
|
||||
|
||||
## Установка и запуск
|
||||
|
||||
### Предварительные требования
|
||||
|
||||
1. **Java 21** или выше
|
||||
2. **MongoDB** (локально или удаленно)
|
||||
3. **Maven 3.6+**
|
||||
|
||||
### Шаги установки
|
||||
|
||||
1. **Клонируйте репозиторий:**
|
||||
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd parser
|
||||
```
|
||||
|
||||
2. **Установите MongoDB:**
|
||||
|
||||
- Скачайте и установите MongoDB с официального сайта
|
||||
- Запустите MongoDB сервис
|
||||
- По умолчанию MongoDB работает на порту 27017
|
||||
|
||||
3. **Настройте конфигурацию:**
|
||||
|
||||
Отредактируйте файл `src/main/resources/application.properties`:
|
||||
|
||||
```properties
|
||||
# MongoDB Configuration
|
||||
spring.data.mongodb.host=localhost
|
||||
spring.data.mongodb.port=27017
|
||||
spring.data.mongodb.database=parser_db
|
||||
|
||||
# RSS Feed URL
|
||||
rss.feed.url=https://kursiv.media/feed/
|
||||
```
|
||||
|
||||
4. **Соберите проект:**
|
||||
|
||||
```bash
|
||||
./mvnw clean compile
|
||||
```
|
||||
|
||||
5. **Запустите приложение:**
|
||||
|
||||
```bash
|
||||
./mvnw spring-boot:run
|
||||
```
|
||||
|
||||
Приложение будет доступно по адресу: `http://localhost:8080`
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### 1. Запуск парсинга Kursiv Media
|
||||
|
||||
```http
|
||||
POST /api/parser/parse/kursiv
|
||||
```
|
||||
|
||||
**Ответ:**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Парсинг Kursiv завершен успешно",
|
||||
"source": "Kursiv",
|
||||
"processedItems": 15,
|
||||
"totalItemsInDb": 25
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Запуск парсинга Kapital.kz
|
||||
|
||||
```http
|
||||
POST /api/parser/parse/kapital
|
||||
```
|
||||
|
||||
**Ответ:**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Парсинг Kapital завершен успешно",
|
||||
"source": "Kapital",
|
||||
"processedItems": 12,
|
||||
"totalItemsInDb": 37
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Запуск парсинга всех источников
|
||||
|
||||
```http
|
||||
POST /api/parser/parse/all
|
||||
```
|
||||
|
||||
**Ответ:**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Парсинг всех источников завершен успешно",
|
||||
"kursivProcessed": 15,
|
||||
"kapitalProcessed": 12,
|
||||
"totalProcessed": 27,
|
||||
"totalItemsInDb": 37
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Получение статистики
|
||||
|
||||
```http
|
||||
GET /api/parser/stats
|
||||
```
|
||||
|
||||
**Ответ:**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"totalItems": 25,
|
||||
"message": "Статистика получена успешно"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Получение всех записей
|
||||
|
||||
```http
|
||||
GET /api/parser/items
|
||||
```
|
||||
|
||||
**Ответ:**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"items": [...],
|
||||
"count": 25,
|
||||
"message": "Записи получены успешно"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Проверка состояния
|
||||
|
||||
```http
|
||||
GET /api/parser/health
|
||||
```
|
||||
|
||||
**Ответ:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "UP",
|
||||
"service": "RSS Parser System",
|
||||
"timestamp": 1703123456789,
|
||||
"scheduler": "Enabled - runs every 30 minutes"
|
||||
}
|
||||
```
|
||||
|
||||
### 4.1. Проверка подключения к MongoDB
|
||||
|
||||
```http
|
||||
GET /api/parser/health/mongodb
|
||||
```
|
||||
|
||||
**Ответ при успешном подключении:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "UP",
|
||||
"message": "MongoDB подключение успешно",
|
||||
"totalItems": 37,
|
||||
"timestamp": 1703123456789
|
||||
}
|
||||
```
|
||||
|
||||
**Ответ при ошибке:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "DOWN",
|
||||
"message": "Ошибка подключения к MongoDB: Command failed with error 13 (Unauthorized)",
|
||||
"suggestion": "Проверьте учетные данные в application.properties",
|
||||
"timestamp": 1703123456789
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Информация о планировщике
|
||||
|
||||
```http
|
||||
GET /api/parser/scheduler/info
|
||||
```
|
||||
|
||||
**Ответ:**
|
||||
|
||||
```json
|
||||
{
|
||||
"schedulerEnabled": true,
|
||||
"cronExpression": "0 0/30 * * * ?",
|
||||
"description": "Запуск каждые 30 минут (в 0 и 30 минут каждого часа)",
|
||||
"nextRun": "Следующий запуск будет в ближайшие 0 или 30 минут часа"
|
||||
}
|
||||
```
|
||||
|
||||
## Структура данных в MongoDB
|
||||
|
||||
Документы сохраняются в коллекции `market_items` со следующей структурой:
|
||||
|
||||
```json
|
||||
{
|
||||
"_id": "ObjectId",
|
||||
"source_name": "Kursiv (Бизнес/экономика)",
|
||||
"url": "https://kursiv.media/article/...",
|
||||
"title": "Заголовок новости",
|
||||
"published_at": "2025-01-14T10:30:00",
|
||||
"added_at": "2025-01-14T12:00:00",
|
||||
"raw_text": "Очищенный от HTML текст статьи...",
|
||||
"hash": "sha256_hash_of_url_and_title",
|
||||
"category": "Бизнес",
|
||||
"analytics": {
|
||||
"summary": null,
|
||||
"sentiment": null,
|
||||
"tags": [],
|
||||
"entities": {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Особенности реализации
|
||||
|
||||
### Дедупликация
|
||||
|
||||
- Каждая запись имеет уникальный хэш, сгенерированный по формуле: `SHA256(url + "::" + title)`
|
||||
- При повторном парсинге существующие записи обновляются (upsert операция)
|
||||
|
||||
### Очистка данных
|
||||
|
||||
- HTML-теги удаляются из текста описания
|
||||
- Даты приводятся к формату `LocalDateTime`
|
||||
- Текстовое содержимое нормализуется
|
||||
|
||||
### Обработка ошибок
|
||||
|
||||
- Логирование всех операций
|
||||
- Graceful handling ошибок парсинга отдельных записей
|
||||
- Продолжение работы при ошибках в отдельных элементах RSS
|
||||
|
||||
### Автоматический планировщик
|
||||
|
||||
- **Автозапуск**: Оба парсера автоматически запускаются каждые 30 минут
|
||||
- **Cron выражение**: `0 0/30 * * * ?` (запуск в 0 и 30 минут каждого часа)
|
||||
- **Параллельная работа**: KursivParserService и KapitalParserService работают независимо
|
||||
- **Логирование**: Все автоматические запуски логируются с эмодзи для удобства мониторинга
|
||||
- **Обработка ошибок**: Ошибки в автоматическом режиме не останавливают планировщик
|
||||
|
||||
### Многопарсерная архитектура
|
||||
|
||||
- **Общая модель данных**: Оба парсера используют одну модель `MarketItem`
|
||||
- **Общая коллекция**: Все новости сохраняются в коллекцию `market_items`
|
||||
- **Дедупликация**: Хэш генерируется одинаково для всех источников
|
||||
- **Разделение источников**: Поле `source_name` позволяет различать источники данных
|
||||
|
||||
## Тестирование
|
||||
|
||||
Запуск тестов:
|
||||
|
||||
```bash
|
||||
./mvnw test
|
||||
```
|
||||
|
||||
Тесты включают:
|
||||
|
||||
- Проверку парсинга RSS-лент обоих источников
|
||||
- Проверку сохранения в MongoDB
|
||||
- Проверку дедупликации
|
||||
- Проверку структуры данных
|
||||
- Проверку работы планировщика
|
||||
- Проверку многопарсерной архитектуры
|
||||
|
||||
## Мониторинг и логирование
|
||||
|
||||
Приложение использует SLF4J для логирования. Уровень логирования можно настроить в `application.properties`:
|
||||
|
||||
```properties
|
||||
logging.level.kz.konturai.parser=DEBUG
|
||||
logging.level.org.springframework.data.mongodb=DEBUG
|
||||
```
|
||||
|
||||
## Возможные проблемы и решения
|
||||
|
||||
### MongoDB требует аутентификацию
|
||||
|
||||
```
|
||||
Command failed with error 13 (Unauthorized): 'Command find requires authentication'
|
||||
```
|
||||
|
||||
**Решение:**
|
||||
|
||||
1. Проверьте учетные данные в `application.properties`
|
||||
2. Убедитесь, что пользователь `parser_user` существует в MongoDB
|
||||
3. Проверьте права доступа пользователя к базе данных `parser_db`
|
||||
4. Используйте endpoint `GET /api/parser/health/mongodb` для диагностики
|
||||
|
||||
**Подробное руководство:** См. файл `MONGODB_TROUBLESHOOTING.md`
|
||||
|
||||
### MongoDB не запущен
|
||||
|
||||
```
|
||||
Error: Could not connect to MongoDB
|
||||
```
|
||||
|
||||
**Решение:** Убедитесь, что MongoDB запущен и доступен на указанном хосте и порту.
|
||||
|
||||
### RSS-лента недоступна
|
||||
|
||||
```
|
||||
Error: Could not fetch RSS feed
|
||||
```
|
||||
|
||||
**Решение:** Проверьте доступность URL RSS-лент и интернет-соединение.
|
||||
|
||||
### Проблемы с кодировкой
|
||||
|
||||
Если возникают проблемы с кодировкой текста, убедитесь, что в системе установлена правильная локаль.
|
||||
|
||||
## Развертывание в продакшене
|
||||
|
||||
1. **Настройте переменные окружения:**
|
||||
|
||||
```bash
|
||||
export SPRING_DATA_MONGODB_HOST=your-mongodb-host
|
||||
export SPRING_DATA_MONGODB_PORT=27017
|
||||
export SPRING_DATA_MONGODB_DATABASE=parser_prod
|
||||
```
|
||||
|
||||
2. **Соберите JAR файл:**
|
||||
|
||||
```bash
|
||||
./mvnw clean package
|
||||
```
|
||||
|
||||
3. **Запустите приложение:**
|
||||
```bash
|
||||
java -jar target/parser-0.0.1-SNAPSHOT.jar
|
||||
```
|
||||
|
||||
## Лицензия
|
||||
|
||||
Этот проект разработан для внутреннего использования в рамках AI-платформы для маркетинговой аналитики.
|
||||
Reference in New Issue
Block a user