Бот анонимных вопросов на телеграм, или квиз бот.
16.11.2023
26.06.2025
10 минут
3063
4
1
0
1
Вступление
Привет в этом кейсе я продемонстрирую тебе, как я сделал своего бота опросника.
Приведу исходный код python. Объясню структуру, и предназначение каждого файла
и обработчика.Ну и конечно сможешь по взаимодействовать с моим, уже готовым ботом.
-
Ты сможешь найти его через:
- Ссылку https://t.me/TimQuizzerBot
- Или вбив название бота, TimQuizzer в телеграме
Увы, когда я его делал, я незадумывал его мультиязычным. А когда спохватился, всё переделывать не решился. Да и
суть данного бота не в мультиязычности. Но к следующему разу, я точно сделаю мультиязычного бота. Так что всем не русскоговорящим будет легче.
Пример создания телеграм бота-опроса.
Структура бота-опроса
Мой бот имеет линейную/последовательную структуру. С некоторыми 'плавающими' обработчиками.
Что я под этим подразумеваю ?
Так как у меня бот-опросник. И он должен задавать вопросы последовательно, один за другим.
То и обработчики, которые обрабатывают ответы пользователя, должны вызываться последовательно, друг за другом.
Под 'плавающими' обработчиками, я имел в виду, те функции, которые могут быть вызваны в любой момент общения с ботом.
-
Их 5:
- /start ➩ Стартует бота. Приветственное сообщение.
- /help ➩ Показывает доступные команды
- /menu ➩ Показывает доступные команды
- /settings ➩ Настройка вывода результата
- /result ➩ Выводит результат опросов людей
-
Структура проекта бота-опросника.
.env ➩ Файл содержащий токен бота. При скачивании с репозитория, его не будет. Нужно сделать его самостоятельно.
data.json ➩ Хранит данные обо всех пользователя. База данных. Да, пока без MySQL и прочих SQL. Создаётся автоматически.
result_template.md ➩ Шаблон, который используется для вывода информации.
requirements.txt ➩ Необходимые пакеты, для работы в виртуальном окружении
main.py ➩ Точка входа. Содержит все обработчики запросов
config.py ➩ Конфигурационный файл. Содержит глобальные переменные.
formaters.py ➩ Функции, суть которых в том, чтобы была возможность изменять вывод результатов в сообщении.
placers.py ➩ Функции взаимодействуюшие с шаблоном. Вставляют данные в него.
utils.py ➩ Различные утилиты.
Команда /start

@bot_dispatcher.message(CommandStart())
async def command_start_handler(message: Message) -> None:
builder = InlineKeyboardBuilder()
for menu_item in menu:
builder.button(text=menu_item, callback_data="menu_"+menu_item)
builder.adjust(2)
await message.answer(f"Привет, *{message.from_user.first_name}*\!\nЯ бот опросник и я могу _провести опрос_ и _показать общие результаты_ опросов других\. \nТакже ты можешь _настроить тип и формат_ выводимой информации\.", reply_markup=builder.as_markup(), parse_mode=ParseMode.MARKDOWN_V2)
Возраст опрашиваемого

@bot_dispatcher.callback_query(F.data == "menu_"+menu[0])
async def your_age_handler(callback: types.CallbackQuery) -> None:
builder = ReplyKeyboardBuilder()
for age in ages:
builder.add(types.KeyboardButton(text=age))
builder.adjust(1)
await callback.message.answer("Твой возраст? ", reply_markup=builder.as_markup(one_time_keyboard=True))
Страна опрашиваемого

@bot_dispatcher.message(F.text.startswith('от') | F.text.contains('до'))
async def your_country_handler(message: Message) -> None:
user_values = {
"user_id": message.from_user.id,
"age": message.text,
"country": None,
"sex": None,
"work": None,
"car": None,
"is_complete": False,
}
with open(f"user_{message.from_user.id}.json", "w", encoding="utf-8") as file:
json.dump(user_values, file)
builder = ReplyKeyboardBuilder()
for contry in countries:
builder.add(types.KeyboardButton(text=f"|{contry['emoji']} {contry['name']}|"))
builder.adjust(5)
await message.answer("Твоя страна? ", reply_markup=builder.as_markup(one_time_keyboard=True))
Пол опрашиваемого

@bot_dispatcher.message(F.text.startswith('|') | F.text.endswith('|'))
async def your_sex_handler(message: Message) -> None:
start_pos = message.text.find(' ') + 1
await update_user(message.from_user.id, 'country', message.text[start_pos:])
builder = ReplyKeyboardBuilder()
builder.add(types.KeyboardButton(text="♂ Мужчина"))
builder.add(types.KeyboardButton(text="♀ Женщина"))
await message.answer("Твой пол? ", reply_markup=builder.as_markup(one_time_keyboard=True))
Работа опрашиваемого

@bot_dispatcher.message(F.text.startswith('♂') | F.text.startswith('♀'))
async def your_work_handler(message: Message) -> None:
start_pos = message.text.find(' ') + 1
await update_user(message.from_user.id, 'sex', message.text[start_pos:])
builder = InlineKeyboardBuilder()
for work in works:
builder.button(text=work, callback_data="work_" + work)
builder.adjust(3)
await message.answer(
"Где работаешь, то есть, какая сфера ?",
reply_markup=builder.as_markup(one_time_keyboard=True)
)
Машина опрашиваемого

@bot_dispatcher.callback_query(F.data.startswith("work_"))
async def your_car_handler(callback: types.CallbackQuery) -> None:
start_pos = callback.data.find('_') + 1
await update_user(callback.from_user.id, 'work', callback.data[start_pos:])
builder = ReplyKeyboardBuilder()
for car in cars:
builder.add(types.KeyboardButton(text=car))
await callback.message.answer("Есть ли у тебя машина ?", reply_markup=builder.as_markup(one_time_keyboard=True))
Конец опроса

@bot_dispatcher.message(F.text.contains("машин"))
async def end_quiz_handler(message: Message) -> None:
await update_user(message.from_user.id, 'car', message.text)
if await is_user_completed(message.from_user.id):
with open(f"user_{message.from_user.id}.json", "r", encoding="utf-8") as file:
user_values = json.load(file)
if not os.path.exists(FILE):
with open(FILE, "a", encoding="utf-8") as file:
file.write("[]")
with open(FILE, "r", encoding="utf-8") as file:
users = json.load(file)
users.append(user_values)
with open(FILE, "w", encoding="utf-8") as file:
json.dump(users, file)
os.remove(f"user_{message.from_user.id}.json")
builder = InlineKeyboardBuilder()
builder.button(text="Результат", callback_data="menu_" + menu[1])
await message.answer("Опрос закончен.\nСпасибо за участие.")
await message.answer("Теперь можно посмотреть на результат.", reply_markup=builder.as_markup())
Главное меню

@bot_dispatcher.message(Command('help', 'menu'))
async def menu_handler(message: Message) -> None:
builder = InlineKeyboardBuilder()
for menu_item in menu:
builder.button(text=menu_item, callback_data="menu_"+menu_item)
builder.adjust(2)
await message.answer(
"""
Комманды для ручного ввода:
\t*/help* или */menu* ➩ Это меню\.
\t*/start* ➩ Общее меню опроса\.
\t*/result* ➩ Результаты опроса участников\.
\t*/settings* ➩ Настройки опросника\.
""",
parse_mode=ParseMode.MARKDOWN_V2)
await message.answer("Или как InlineButtons", reply_markup=builder.as_markup())
Настройки

Данный обработчик разбит на 4 функции. Одна, *setting_update_format_numbers*,
реализует непосредственно функционал изменения формата отображаемой информации.
@bot_dispatcher.callback_query(F.data.contains("format_setting_"))
async def setting_update_format_numbers(callback: types.CallbackQuery):
builder = InlineKeyboardBuilder()
for set_menu in format_settings_menu:
if set_menu in callback.data:
builder.button(text="+ " + set_menu, callback_data="format_setting_"+set_menu)
global division_type
division_type = set_menu
else:
builder.button(text=set_menu, callback_data="format_setting_"+set_menu)
builder.adjust(2)
await callback.bot.edit_message_reply_markup(chat_id=callback.message.chat.id, message_id=callback.message.message_id, reply_markup=builder.as_markup())
Другая, *setting*, показывает возможные настройки, создаёт соответствующие
кнопки.
async def setting(message: Message) -> None:
builder = InlineKeyboardBuilder()
for set_menu in format_settings_menu:
builder.button(text=set_menu, callback_data="format_setting_"+set_menu)
builder.adjust(2)
await message.answer("Настройки формата", reply_markup=builder.as_markup())
И две другие реализованы через *callback_query* и *message*. И обе они вызывают
*setting*. Сделано это было для того, чтобы была возможность работать с этой функцией,
и как с командой и как кнопкой.
@bot_dispatcher.message(Command("settings"))
async def setting_command_handler(message: Message) -> None:
await setting(message)
@bot_dispatcher.callback_query(F.data == "menu_"+menu[2])
async def setting_callback_handler(callback: types.CallbackQuery):
await setting(callback.message)
Результат

@bot_dispatcher.message(Command("result"))
async def result_command_handler(message: Message) -> None:
await result(message)
@bot_dispatcher.callback_query(F.data == "menu_"+menu[1])
async def result_callback_handler(callback: types.CallbackQuery) -> None:
await result(callback.message)
Сам же обработчик *result*, занимается тем что форматирует result_template.md.
Вставляет данные при помощи функций из *placers.py*. А формат меняет при помощи *formaters.py*
async def result(message: Message) -> None:
if not os.path.exists(FILE):
builder = InlineKeyboardBuilder()
builder.button(text="Начать", callback_data="menu_" + menu[0])
await message.answer("Извини, база данных пуста. Пройди опрос первым !", reply_markup=builder.as_markup())
return
with open(FILE, "r", encoding="utf-8") as file:
users = json.load(file)
with open("result_template.md", "r", encoding="utf-8") as file:
template = file.read()
# Define result output
result = template.replace("divisiontype", division_type)
# Result output in absolute numbers
if division_type == format_settings_menu[0]:
result = place_age(result, users, in_absolute)
result = place_country(result, users, in_absolute)
result = place_sex(result, users, in_absolute)
result = place_work(result, users, in_absolute)
result = place_car(result, users, in_absolute)
else:
result = place_age(result, users, in_percent)
result = place_country(result, users, in_percent)
result = place_sex(result, users, in_percent)
result = place_work(result, users, in_percent)
result = place_car(result, users, in_percent)
await message.answer(result, parse_mode=ParseMode.MARKDOWN_V2)
Скачать готового телеграм бота, или скопировать код
Ты можешь скачать бота с моего репозитория.
TimQuizzer-bot
Или ты можешь просмотреть исходный код, ниже. Скопировав интересующие тебя части
main.py
config.py
formaters.py
placers.py
utils.py
result_template.md
Заключение
Вот так вот я написал своего квиз бота. Возможно вам покажется он простеньким, и вы вцелом будете правы.
Но нужно же публиковать статьи, верно? В любом случае, надеюсь данный кейс сможет помочь тебе в написании
собственного бота опросника.
Комментарии
(0)
Отправить
Ответ для
>
Сейчас тут пусто. Буть первым (o゚v゚)ノ
Другое
Похожие статьи
Использованные термины
- Телеграм бот ⟶ Это программа, которая используя **API** телеграма может выполнять различные действия в чатах без человека.
- aiogram ⟶ Это фреймворк, который построен на модуля питона *asyncio* и *aiohttp*, для создания телеграм ботов. Полностью *ассинхронный*.
- VPS (Виртуальный частный сервер) ⟶ Это услуга суть которой заключается в том что предоставляется доступ к выделеному серверу на определённой машине. Таких выделенных серверов на одной машине может быть тысячи. Обычно управление таким сервером не отличается от управления обычным, физическим.
- Сериализатор ⟶ Сериализаторы позволяют преобразовывать сложные данные, такие как наборы запросов и экземпляры моделей, в собственные типы данных Python, которые затем могут быть легко преобразованы в JSON, XML или другие типы содержимого.
- Отрисовка на стороне сервера(ОСС) ⟶ Это метод, используемый в веб-разработке, который включает использование сценариев на веб-сервере, который создает ответ, настроенный для каждого запроса пользователя к веб-сайту. Сценарии могут быть написаны на любом из доступных серверных языков сценариев.
Релевантные вопросы
- Для чего нужен телеграм бот Телеграм боты могут использоваться по разным причинам. Они являются универсальными помощниками в бизнесе, могут предоставлять удобный формат взаимодействия с клиентами или быть отличной платформой для размещения сайта или инструмента.
- Подходит ли Python для создания ботов Python является одним из самых популярных языков программирования для разработки ботов. Он очень простой и интуитивно понятный. Это отличным выбором для новичков. Так же python имеет в своей коллекции огромное количество библиотек, которые упростят вам жизнь и работу.
- Что не умеют делать чат-боты Несмотря на то, что chatgpt захватывает всё больше и больше пользователей в своё влияние, чат-боты до сих пор плохо решают индивидуальные запросы и жалобы пользователей. Они не смогут вам найти новых клиентов, и сэкономить денег они тоже не помогут.