Написать пост

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

Аватарка пользователя Елена Капаца

Рассказали, как создать привлекающего на курс по управлению проектами Telegram-бота на aiogram, с полным разбором кода.

Обложка поста Из цикла ETL: Создаем Tripwire-бота на aiogram, часть 1

Представьте: вам как Python-разработчику доверили написать бота, но с чего начать?

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

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

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

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

Запуск бота

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

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

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

			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 и проследуйте стандартным шагам. Подробнее в этом гайде.

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

			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. Через неё пользователь будет попадать к первому одноименному обработчику, который проверит наличие человека в базе данных и запросит телефон, если человек новый:

			@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 выглядит следующим образом:

			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:

			@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))
		

Опросник

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

			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 примет «это на свой счёт»:

Из цикла ETL: Создаем Tripwire-бота на aiogram, часть 1 3
			@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):

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

Заключение

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

Если вы захотите форкнуть такого бота, то вот ссылка на репозиторий.

Следите за новыми постами
Следите за новыми постами по любимым темам
969 открытий2К показов