1
0
Fork 0
mirror of https://github.com/EDeev/npr_meteobot.git synced 2026-10-08 04:59:33 +03:00

Compare commits

..

5 commits

Author SHA1 Message Date
69830f156f README на русском и английском 2026-10-02 23:36:49 +00:00
646943c21e requirements.txt и CI (ruff, создание базы) 2026-10-02 23:36:49 +00:00
28a5170be0 Мелкие исправления по ruff: дублирующееся имя обработчика /weather, неиспользуемые переменные 2026-10-02 23:36:49 +00:00
f223570bab Токен из окружения, база создаётся сама
- токен бота — из BOT_TOKEN, а не из config.py;
- sub.db (с идентификатором подписчика) убран из git: SQLighter создаёт таблицы и
  служебные строки из schema.sql, если базы нет.
2026-10-02 23:36:49 +00:00
be4411e269 Переводы строк приведены к LF 2026-10-02 23:33:14 +00:00
12 changed files with 480 additions and 475 deletions

2
.gitattributes vendored Normal file
View file

@ -0,0 +1,2 @@
* text=auto eol=lf
*.db binary

21
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,21 @@
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.10"
- run: pip install ruff==0.14.0
- name: Ruff (синтаксис и ошибки)
run: ruff check --select E9,F .
- name: База создаётся из schema.sql
run: |
python -c "import sql; db = sql.SQLighter('/tmp/t.db'); db.add_user('1'); assert db.user_exists('1')"

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
__pycache__/
*.py[cod]
.venv/
.env
*.db

41
README.en.md Normal file
View file

@ -0,0 +1,41 @@
# NPR MeteoBot
[Русский](README.md) · **English**
[![CI](https://github.com/EDeev/npr_meteobot/actions/workflows/ci.yml/badge.svg)](https://github.com/EDeev/npr_meteobot/actions/workflows/ci.yml)
A Telegram bot for schoolchildren in the Norilsk industrial area: it sends class cancellations due to frost
and wind ("aktirovka") for the user's shift and district and shows the weather forecast.
**Status:** school project (2022), completed, archived
**Stack:** Python 3.10 · aiogram 2 · SQLite · Selenium + BeautifulSoup (city administration site, Gismeteo) · pymorphy2
- Subscription to cancellations by shift (1 or 2) and district: Norilsk, Talnakh, Oganer, Kayerkan
- Regular checks of the administration site and broadcasts to subscribers
- Weather forecast for the day and up to 10 days ahead (Gismeteo data)
## Running
```bash
pip install -r requirements.txt
BOT_TOKEN=token_from_BotFather python bot.py
```
The `sub.db` database is created on first run from `schema.sql`. Cancellations need Chrome: the
administration site is read with Selenium.
## License
School project (2022). The code is open for study; there is no separate license.
## Author
**Egor Deev** — [GitHub](https://github.com/EDeev) · [Telegram](https://t.me/DeevEgor) · [egor@deev.space](mailto:egor@deev.space)
---
<div align="center">
<sub>⭐ If you find this project useful, give it a star on GitHub!</sub>
<p><sub>Made with ❤️ — <a href="https://deev.space">deev.space</a></sub></p>
</div>

138
README.md
View file

@ -1,139 +1,41 @@
# NPR MeteoBot
Автоматизированная система мониторинга метеорологических условий и уведомлений об актировках учебных занятий для Норильского промышленного района (НПР).
**Русский** · [English](README.en.md)
## 📋 Описание проекта
[![CI](https://github.com/EDeev/npr_meteobot/actions/workflows/ci.yml/badge.svg)](https://github.com/EDeev/npr_meteobot/actions/workflows/ci.yml)
NPR MeteoBot представляет собой интеллектуальную систему на базе Telegram-бота, предназначенную для:
- Мониторинга погодных условий в четырех районах НПР
- Автоматического отслеживания актировок учебных занятий
- Персонализированных уведомлений пользователей
- Предоставления детализированных метеорологических данных
Telegram-бот для школьников Норильского промышленного района: присылает актировки (отмену занятий
из-за мороза и ветра) для своей смены и района и показывает прогноз погоды.
### Основные возможности:
- **Персонализация**: Настройка по смене обучения и району проживания
- **Автоматизация**: Регулярный мониторинг официальных источников
- **Уведомления**: Система подписок с гибкими настройками
- **Актуальность**: Интеграция с Gismeteo и официальным сайтом города
**Статус:** школьный проект (2022), завершён, в архиве
## 🏗️ Архитектура системы
**Стек:** Python 3.10 · aiogram 2 · SQLite · Selenium + BeautifulSoup (сайт администрации, Gismeteo) · pymorphy2
### Компоненты:
- `bot.py` - Основной модуль Telegram-бота с обработкой команд
- `sql.py` - Модуль работы с базой данных SQLite
- `info.py` - Парсинг данных с внешних источников
- `config.py` - Конфигурационные параметры системы
- Подписка на актировки по смене (1 или 2) и району: Норильск, Талнах, Оганер, Кайеркан
- Регулярная проверка сайта администрации и рассылка подписчикам
- Прогноз погоды на день и на 10 дней вперёд (данные Gismeteo)
### Структура базы данных:
- **users**: Профили пользователей с настройками
- **weather**: Кэш метеорологических данных
- **parts**: Данные об актировках по сменам
- **data**: Системная информация
## Запуск
## 🛠️ Технологический стек
### Backend:
- **Python 3.7+** - Основной язык разработки
- **aiogram 2.x** - Фреймворк для Telegram Bot API
- **SQLite** - Локальная база данных
- **asyncio** - Асинхронное программирование
### Парсинг данных:
- **Selenium WebDriver** - Автоматизация браузера
- **BeautifulSoup4** - HTML-парсинг
- **requests** - HTTP-запросы
### Обработка данных:
- **pymorphy2** - Морфологический анализ русского языка
## 🚀 Установка и настройка
### Предварительные требования:
```python
# Установка ChromeDriver для Selenium
# Ubuntu/Debian:
sudo apt-get install chromium-chromedriver
# Windows: загрузить с https://chromedriver.chromium.org/
```
### Установка зависимостей:
```python
```bash
pip install -r requirements.txt
BOT_TOKEN=токен_от_BotFather python bot.py
```
### Конфигурация:
1. Получите токен бота в [@BotFather](https://t.me/BotFather)
2. Обновите `API_TOKEN` в `config.py`
3. Создайте структуру базы данных SQLite
База `sub.db` создаётся при первом запуске из `schema.sql`. Для актировок нужен Chrome: сайт
администрации читается через Selenium.
### Запуск:
```python
python bot.py
```
## Лицензия
## 📊 Функциональные возможности
Школьный проект (2022). Код открыт для изучения, отдельной лицензии нет.
### Команды бота:
- `/start` - Инициализация и настройка профиля
- `/town` - Изменение города и смены обучения
- `/acta` - Просмотр текущих актировок
- `/weather` - Детализированный прогноз погоды
- `/storm` - Штормовые предупреждения
- `/letter` - Управление подпиской на уведомления
- `/notice` - Настройка типа уведомлений
## Автор
### Автоматические процессы:
- **timer()** - Мониторинг актировок (каждую минуту)
- **wind()** - Обновление погодных данных (каждые 20 минут)
- **clear()** - Очистка устаревших данных (каждые 5 минут)
## 🎯 Целевые районы
Система обслуживает четыре района НПР:
- **Центральный район** (Норильск)
- **Район Талнах**
- **Район Оганер**
- **Район Кайеркан**
## 🔧 Конфигурационные параметры
### Временные интервалы мониторинга:
- Прогноз погоды: 1, 4, 7, 10, 13, 16, 19, 22 часа
- Проверка актировок: ежеминутно
- Обновление погоды: каждые 20 минут
### Источники данных:
- **Актировки**: [norilsk-city.ru/meteo](https://www.norilsk-city.ru/meteo/)
- **Погода**: [gismeteo.ru](https://www.gismeteo.ru/)
## 📈 Масштабируемость
Система спроектирована для:
- Обработки 17,000+ активных пользователей
- Асинхронной обработки запросов
- Отказоустойчивой работы с внешними API
## ⚠️ Ограничения
- Зависимость от доступности внешних источников данных
- Требует настройки ChromeDriver для корректного парсинга
- Локальная SQLite база данных (не подходит для кластерного развертывания)
## 📝 Лицензия
Проект разработан для образовательных и некоммерческих целей.
## 👥 Автор
**Деев Егор Викторович** - Backend Developer
- GitHub: [@EDeev](https://github.com/EDeev)
- Email: egor@deev.space
- Telegram: [@Egor_Deev](https://t.me/Egor_Deev)
**Деев Егор Викторович** — [GitHub](https://github.com/EDeev) · [Telegram](https://t.me/DeevEgor) · [egor@deev.space](mailto:egor@deev.space)
---
<div align="center">
<sub>Разработано с использованием современных технологий асинхронного программирования и автоматизации веб-парсинга.</sub>
<p><sub>Создано с ❤️ от вашего дорогого - deev.space ©</sub></p>
<sub>⭐ Если проект оказался полезным, поставьте звёздочку на GitHub!</sub>
<p><sub>Сделано с ❤️ — <a href="https://deev.space">deev.space</a></sub></p>
</div>

2
bot.py
View file

@ -157,7 +157,7 @@ async def act(message: types.Message):
@dp.message_handler(commands=['weather'])
async def storm(message: types.Message):
async def weather_command(message: types.Message):
text = message.text.split()
try:
day = int(text[1])

View file

@ -1,5 +1,7 @@
API_TOKEN = 'token from BotFather' # ОСНОВНОЙ
# API_TOKEN = 'token from BotFather' # ТЕСТЫ
import os
# Токен бота от @BotFather — из переменной окружения BOT_TOKEN
API_TOKEN = os.environ.get('BOT_TOKEN', '')
CITY = {'Центральный район': [1, 'Норильск'], 'район Талнах': [2, 'Талнах'],
'ж/о Оганер': [3, 'Оганер'], 'район Кайеркан': [4, 'Кайеркан']}

View file

@ -22,7 +22,7 @@ def act():
acta[acta.index(lst)] = [config.CITY[lst[0]], int(lst[1].split("-")[1].split()[0])]
return sorted(acta), count
except Exception as e:
except Exception:
return [], ""
@ -57,7 +57,7 @@ def weather(moment):
dire = soup.find_all("div", class_="direction")
prec = soup.find_all("div", class_="item-unit")
k, s, weather = 0, 0, {}
weather = {}
for i in range(8):
par = wind[i].get_text().split()[0].split('-')

6
requirements.txt Normal file
View file

@ -0,0 +1,6 @@
aiogram==2.25.2
pymorphy2==0.9.1
pymorphy2-dicts-ru==2.4.417127.4579844
selenium==4.15.2
beautifulsoup4==4.12.3
requests==2.31.0

15
schema.sql Normal file
View file

@ -0,0 +1,15 @@
-- Схема базы бота и служебные строки, которые он ожидает (подписчиков нет)
CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, id_user VARCHAR (255) NOT NULL,
rating INTEGER (4) NOT NULL DEFAULT (0), status BOOLEAN NOT NULL DEFAULT (False),
send BOOLEAN NOT NULL DEFAULT (True), part INTEGER (1) NOT NULL, city INTEGER (1) NOT NULL);
CREATE TABLE IF NOT EXISTS parts (part INTEGER PRIMARY KEY AUTOINCREMENT, nor VARCHAR (3), tal VARCHAR (3),
oga VARCHAR (3), kae VARCHAR (3));
CREATE TABLE IF NOT EXISTS weather (id STRING, "1" VARCHAR, "4" VARCHAR, "7" VARCHAR, "10" VARCHAR,
"13" VARCHAR, "16" VARCHAR, "19" VARCHAR, "22" VARCHAR);
CREATE TABLE IF NOT EXISTS data (id INTEGER PRIMARY KEY AUTOINCREMENT, date DATE NOT NULL, part INTEGER (2) NOT NULL,
weath STRING);
INSERT INTO parts (part, nor, tal, oga, kae) VALUES (1, '11', '11', '11', '11'), (2, '11', '11', '11', '11');
INSERT INTO weather (id) VALUES (' '), ('tomorrow'), ('3-day'), ('4-day'), ('5-day'), ('6-day'), ('7-day'),
('8-day'), ('9-day'), ('10-day');
INSERT INTO data (id, date, part) VALUES (1, '2022-02-24', 1);

11
sql.py
View file

@ -1,11 +1,22 @@
import os
import sqlite3
SCHEMA = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'schema.sql')
class SQLighter:
def __init__(self, database):
"""Подключаемся к БД и сохраняем курсор соединения"""
self.connection = sqlite3.connect(database)
self.cursor = self.connection.cursor()
self._create_if_empty()
def _create_if_empty(self):
"""Новая база: создаём таблицы и служебные строки из schema.sql"""
exists = self.cursor.execute("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'users'").fetchone()
if not exists:
with open(SCHEMA, encoding='utf-8') as f:
self.connection.executescript(f.read())
def user_exists(self, id_user):
"""Проверяем, есть ли уже пользователь в базе"""

BIN
sub.db

Binary file not shown.