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

Compare commits

..

No commits in common. "69830f156f0f33e350c284cd63455490372462a4" and "6c60731a2cb0bdb886e4662b94232a0dec7671d7" have entirely different histories.

12 changed files with 476 additions and 481 deletions

2
.gitattributes vendored
View file

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

View file

@ -1,21 +0,0 @@
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
View file

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

View file

@ -1,41 +0,0 @@
# 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>

140
README.md
View file

@ -1,41 +1,139 @@
# NPR MeteoBot # 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) ## 📋 Описание проекта
Telegram-бот для школьников Норильского промышленного района: присылает актировки (отмену занятий NPR MeteoBot представляет собой интеллектуальную систему на базе Telegram-бота, предназначенную для:
из-за мороза и ветра) для своей смены и района и показывает прогноз погоды. - Мониторинга погодных условий в четырех районах НПР
- Автоматического отслеживания актировок учебных занятий
- Персонализированных уведомлений пользователей
- Предоставления детализированных метеорологических данных
**Статус:** школьный проект (2022), завершён, в архиве ### Основные возможности:
- **Персонализация**: Настройка по смене обучения и району проживания
- **Автоматизация**: Регулярный мониторинг официальных источников
- **Уведомления**: Система подписок с гибкими настройками
- **Актуальность**: Интеграция с Gismeteo и официальным сайтом города
**Стек:** Python 3.10 · aiogram 2 · SQLite · Selenium + BeautifulSoup (сайт администрации, Gismeteo) · pymorphy2 ## 🏗️ Архитектура системы
- Подписка на актировки по смене (1 или 2) и району: Норильск, Талнах, Оганер, Кайеркан ### Компоненты:
- Регулярная проверка сайта администрации и рассылка подписчикам - `bot.py` - Основной модуль Telegram-бота с обработкой команд
- Прогноз погоды на день и на 10 дней вперёд (данные Gismeteo) - `sql.py` - Модуль работы с базой данных SQLite
- `info.py` - Парсинг данных с внешних источников
- `config.py` - Конфигурационные параметры системы
## Запуск ### Структура базы данных:
- **users**: Профили пользователей с настройками
- **weather**: Кэш метеорологических данных
- **parts**: Данные об актировках по сменам
- **data**: Системная информация
```bash ## 🛠️ Технологический стек
pip install -r requirements.txt
BOT_TOKEN=токен_от_BotFather python bot.py ### 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/
``` ```
База `sub.db` создаётся при первом запуске из `schema.sql`. Для актировок нужен Chrome: сайт ### Установка зависимостей:
администрации читается через Selenium. ```python
pip install -r requirements.txt
```
## Лицензия ### Конфигурация:
1. Получите токен бота в [@BotFather](https://t.me/BotFather)
2. Обновите `API_TOKEN` в `config.py`
3. Создайте структуру базы данных SQLite
Школьный проект (2022). Код открыт для изучения, отдельной лицензии нет. ### Запуск:
```python
python bot.py
```
## Автор ## 📊 Функциональные возможности
**Деев Егор Викторович** — [GitHub](https://github.com/EDeev) · [Telegram](https://t.me/DeevEgor) · [egor@deev.space](mailto:egor@deev.space) ### Команды бота:
- `/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)
--- ---
<div align="center"> <div align="center">
<sub>⭐ Если проект оказался полезным, поставьте звёздочку на GitHub!</sub> <sub>Разработано с использованием современных технологий асинхронного программирования и автоматизации веб-парсинга.</sub>
<p><sub>Сделано с ❤️ — <a href="https://deev.space">deev.space</a></sub></p> <p><sub>Создано с ❤️ от вашего дорогого - deev.space ©</sub></p>
</div> </div>

2
bot.py
View file

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

View file

@ -1,7 +1,5 @@
import os API_TOKEN = 'token from BotFather' # ОСНОВНОЙ
# API_TOKEN = 'token from BotFather' # ТЕСТЫ
# Токен бота от @BotFather — из переменной окружения BOT_TOKEN
API_TOKEN = os.environ.get('BOT_TOKEN', '')
CITY = {'Центральный район': [1, 'Норильск'], 'район Талнах': [2, 'Талнах'], CITY = {'Центральный район': [1, 'Норильск'], 'район Талнах': [2, 'Талнах'],
'ж/о Оганер': [3, 'Оганер'], 'район Кайеркан': [4, 'Кайеркан']} 'ж/о Оганер': [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])] acta[acta.index(lst)] = [config.CITY[lst[0]], int(lst[1].split("-")[1].split()[0])]
return sorted(acta), count return sorted(acta), count
except Exception: except Exception as e:
return [], "" return [], ""
@ -57,7 +57,7 @@ def weather(moment):
dire = soup.find_all("div", class_="direction") dire = soup.find_all("div", class_="direction")
prec = soup.find_all("div", class_="item-unit") prec = soup.find_all("div", class_="item-unit")
weather = {} k, s, weather = 0, 0, {}
for i in range(8): for i in range(8):
par = wind[i].get_text().split()[0].split('-') par = wind[i].get_text().split()[0].split('-')

View file

@ -1,6 +0,0 @@
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

View file

@ -1,15 +0,0 @@
-- Схема базы бота и служебные строки, которые он ожидает (подписчиков нет)
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,22 +1,11 @@
import os
import sqlite3 import sqlite3
SCHEMA = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'schema.sql')
class SQLighter: class SQLighter:
def __init__(self, database): def __init__(self, database):
"""Подключаемся к БД и сохраняем курсор соединения""" """Подключаемся к БД и сохраняем курсор соединения"""
self.connection = sqlite3.connect(database) self.connection = sqlite3.connect(database)
self.cursor = self.connection.cursor() 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): def user_exists(self, id_user):
"""Проверяем, есть ли уже пользователь в базе""" """Проверяем, есть ли уже пользователь в базе"""

BIN
sub.db Normal file

Binary file not shown.