Ques/Help/Req Из цикла ETL: Создаем Tripwire-бота на aiogram, часть 1

XakeR

Member
Регистрация
13.05.2006
Сообщения
1 912
Реакции
0
Баллы
16
Местоположение
Ukraine
Представьте: вам как Python-разработчику доверили написать бота, но с чего начать?

Это статья из цикла «5 ETL для зоопарка ботов». В нём я пошагово разбираю, как наладить потоки данных из разных библиотек и конструкторов ботов на разных языках и стеках. В основе лежат Python и его библиотеки. Вот предыдущие статьи цикла:

  • Анонс цикла с перечнем технологий
  • Настройка потока логов «Из Dialogflow в BigQuery»
  • Python для аналитики ad hoc из BigQuery
  • Развертывание Airflow
  • Настройка первого DAG

Если Вы уже знаете, как исполнять в коде SQL-запросы, понимаете основы ЯП достаточно, чтобы писать несложные программы, то бот может стать вашим следующим этапом профессионального развития: он позволит закрепить основы и связать их воедино. В дополнение ко всему, автоматизация рабочего процесса станет бонусом вам или вашим коллегам.

Мы получим довольно простого бота, который задаёт будущим студентам курса вовлекающие вопросы и оценивает навык управления проектами. И выводит:

  • количество очков (рассчитывается по нелинейной формуле);
  • график-паутинку на базе очков;
  • индивидуальную рекомендацию курсов.

Бот, опрашивающий студентов0


Запуск бота​


Подключаем aiogram. Это фреймворк, а значит, взаимосвязанных скриптов в проекте немало:

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


Чтобы сервер понимал, с какого именно файла начать, в main.py добавляем условие if __name__ == ‘__main__’:

main.py:

from aiogram import executor import handlers from loader import dp if __name__ == ‘__main__’: executor.start_polling(dp) Поллинг (start_polling) — базовый способ «выпустить» бота в мир. Существует еще и вебхук-бот, но для его развёртывания требуется доменное имя, которому можно добавить A-запись, так что пока обойдемся простейшим решением.

В loader.py прописываем основные конфиденциальные настройки, которые будет брать бот:

import logging from aiogram import Bot, Dispatcher, types from aiogram.contrib.fsm_storage.memory import MemoryStorage from core import settings bot = Bot(token=settings.tg_token, parse_mode=types.ParseMode.MARKDOWN_V2) storage = MemoryStorage() dp = Dispatcher(bot, storage=storage) logging.basicConfig(level=logging.INFO)

Здесь указано, где брать токен, какой режим парсинга текста использовать и так далее.

Кстати, если вы еще не взаимодействовали с @BotFather и не создали своего бота, то отправьте ему /start, затем /newbot и проследуйте стандартным шагам. Подробнее в этом гайде.

Ведущий аналитик/программист (Отдел планирования и управленческой отчетности) МТС, , можно удалённо, По итогам собеседования tproger.ru Вакансии на tproger.ru

Пишем модуль settings, из которого потом будем брать токен:

settings.py

import os from dotenv import load_dotenv load_dotenv() tg_token = str(os.getenv(‘TELEGRAM_TOKEN’)) TELEGRAM_BOT_NAME = str(os.getenv(‘TELEGRAM_BOT_NAME’)) ADMINS = str(os.getenv(‘BOT_ADMINS’)) DATABASE = str(os.getenv(‘DATABASE’)) SKIP_CHECK_TIME = bool(os.getenv(‘SKIP_CHECK_TIME’))

os.getenv() ссылается на некоторые переменные вроде TELEGRAM TOKEN и DATABASE. Их мы поместим в отдельный локальный файл .env. Разработка и деплой бота ведутся на разных машинах, и это поможет не переписывать его при переходе, например, с macOS на Linux SYSTEM_PATH:

.env

TELEGRAM_TOKEN=<TOKEN> BOT_ADMINS=<ID АДМИНА> DATABASE=./data/db.sqlite3 # Путь до файлов с графиками SYSTEM_PATH=/Users/elenakapatsa/Repositories/tripwire/radar_charts/

Пишем команду /start. Через неё пользователь будет попадать к первому одноименному обработчику, который проверит наличие человека в базе данных и запросит телефон, если человек новый:

start.py

@dp.message_handler(commands=[‘start’], state=None) async def start(message: types.Message): tg_id = message.chat.id # Определяем ID юзера для записи в БД # Если юзер новый, то запрашиваем телефон if not bd.check_user(tg_id): await ask_phone(tg_id, message.chat.first_name) # Если юзер не новый, отправляем его на первый вопрос else: await message.answer(texts.initialize_questionnaire, reply_markup=kb.add_step_keyboard(texts_btn.start_menu))

Функция ask_phone выглядит следующим образом:

start.py

async def ask_phone(tg_id, first_name): phone = kb.send_phone() # Рендерим кнопку “Отправить телефон” name = md.bold(first_name) # Выделяем имя из профиля # Просим юзера показать телефон await bot.send_message(tg_id, f»’Привет, {name}! Для регистрации нажми кнопку Передать номер телефона»’, reply_markup=phone)

Функция get_phone() захватит телефон, имя и Telegram ID и запишет это в базу SQLite:

start.py

@dp.message_handler(content_types=types.ContentTypes.CONTACT) async def get_phone(message: types.Message): phone = message.contact.phone_number name = message.contact.first_name tg_id = message.chat.id # Запишем в базу данные юзера bd.registration(tg_id, phone, name) # Запустим опрос await message.answer(md.text( # Зададим вопрос texts.initialize_questionnaire, sep=’n’), reply_markup=kb.add_step_keyboard(texts_btn.start_menu))

Опросник​


Импортируем необходимые библиотеки. По мере раскомментирования кода станет понятно, для чего нужна каждая из них:

questionnaire.py

from aiogram import md, types from aiogram.dispatcher import FSMContext from aiogram.dispatcher.filters import Text from keyboards import keyboards as kb from loader import dp from states import states as st from texts import numeric_keyboard as nk from texts import text_buttons as tb from texts import texts from texts import questions from utils import bd from plotter_interpreter import * from level_counter import *

Чтобы попасть в саму анкету, пользователь будет нажимать клавишу «Поехали» (первую в списке, то есть нулевую по канонам ЯП) и хэндлер analyst_start примет «это на свой счёт»:

Запрос телефона в aiogram2

@dp.message_handler(Text(equals=tb.start_menu[0], ignore_case=True), state=’*’) async def analyst_start(message: types.Message): await st.StateQuestionnaire.question1.set() await message.answer(questions.team_problems, reply_markup=kb.add_step_keyboard(nk.numeric_keyboard[:6]))

База SQLite выглядит так (для просмотра пользуюсь DB Browser for SQLite):

База данных SQLite для бота-опросника3


Заключение​


Чтобы сохранить простоту восприятия, я разделила разбор кода на части. В этой мы узнали, как запустить бота в режиме разработки, как общаться с BotFather, как запрашивать пользовательские данные и записывать их. В следующей статье я расскажу, как рассчитываются паутинка, итоговое количество очков и рекомендация курса. И покажу, как выгружать базу игроков в Google Таблицы.

Если вы захотите форкнуть такого бота, то вот ссылка на репозиторий.
 
198 157Темы
635 128Сообщения
3 618 411Пользователи
Semifistokl22Новый пользователь
Верх