Урок 1. Быстрый старт. Эхо-бот
Перед началом убедитесь, что у вас установлен интерпретатор языка Python версии не ниже 3.6 (актуальные версии посмотреть и скачать можно здесь). Первый и второй уроки будут проведены на версии 3.6.4, версия библиотеки aiogram 1.0.4 , проверено на версии 1.1.
Этот пункт можно пропустить, если вы не новичок, и уже всё проверили.
Проверить версию интерпретатора можно следующим образом (справедливо для большинства систем): python —version . Будет возвращено Python 3.6.4 . Если у вас установлено несколько версий интерпретатора, будет необходимо указать версию: python3 —version .
Далее устанавливаем библиотеку командой pip install -U aiogram . Если у вас установлено несколько интерпретаторов (например 2 и 3), то необходимо явно указать версию pip: pip3 install -U aiogram . Если у вас установлено несколько версий 3 (например 3.4, 3.5, 3.6), то обращаемся к необходимому интерпретатору командой -m pip . , то есть в данном случае python3.6 -m pip install -U aiogram . Проверить версию библиотеки можно командой pip freeze | grep aiogram (тут так же не забудьте правильно указать версию pip), вернется aiogram==1.0.4 . Возможно, у вас в Windows не будет работать команда grep , тогда используйте просто команду pip freeze и убедитесь в присутствии aiogram в результате выполнения команды.
Начинаем писать код
Давайте для знакомства с библиотекой создадим бота, который будет приветствовать пользователя и высылать в ответ присланный ему текст. Для этого создадим каталог для нашего бота и сохраним там два файла: bot.py и config.py .
Открываем последний любимым текстовым редактором и записываем туда токен, полученный от @BotFather:
TOKEN = '123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11'
Теперь возьмемся за основной файл — приступаем к редактированию файла bot.py . Для этого импортируем необходимые модули библиотеки aiogram и токен бота, а так же инициализируем объекты бота и диспетчера:
from aiogram import Bot, types from aiogram.dispatcher import Dispatcher from aiogram.utils import executor from config import TOKEN bot = Bot(token=TOKEN) dp = Dispatcher(bot)
Команда, с которой начинается общение пользователя с ботом — /start . Поэтому давайте научим нашего бота реагировать на эту команду. Создаем message_handler и объявляем там функцию ответа:
@dp.message_handler(commands=['start']) async def process_start_command(message: types.Message): await message.reply("Привет!\nНапиши мне что-нибудь!")
Ещё в ботах принято создавать обработчик команды /help — вдруг пользователь заинтересуется возможностями бота.
Вообще, мы могли бы добавить просто help в массив, передаваемый параметру commands , чтобы получилось:
@dp.message_handler(commands=['start', 'help'])
Но зачем приветствовать пользователя снова? Поэтому создадим отдельный message_handler для этой команды:
@dp.message_handler(commands=['help']) async def process_help_command(message: types.Message): await message.reply("Напиши мне что-нибудь, и я отпрпавлю этот текст тебе в ответ!")
Обращу внимание новичка на то, что называть функции можно как угодно — хоть abc , хоть qwerty , однако называя функции понятным языком — process_start_command , process_help_command сразу понятно, какая за что отвечает. Главное, чтобы имена не повторялись. Называть как угодно можно также и имя параметра, покажу дальше.
Итак! Осталось сделать обработку текстового сообщения. Для этого пишем следующее:
@dp.message_handler() async def echo_message(msg: types.Message): await bot.send_message(msg.from_user.id, msg.text)
Объясняю, что мы только что написали:
Если не указывать тип обрабатываемого сообщения, то библиотека по умолчанию делает обработку только текстовых сообщений — то, что нам и нужно. Поэтому скобки на первой строчке остаются пустыми.
Параметр msg это всё то же сообщение, как и в предыдущих пунктах.
В данном случае на последней строчке мы отправляем пользователю сообщение не ответом, а простым сообщением. Для этого мы воспользовались методом send_message и передали в него два обязательных параметра — айди чата, куда отправляем, и сам текст сообщения. Их мы взяли из объекта msg, который является представителем класса Message. Параметр from_user ссылается на ещё один объект — данный параметр имеет класс User. У него есть параметр id — уникальный идентификатор для чатов и каналов в телеграме. Ну и текст полученного сообщения мы получили из поля text.
Финальный штрих
Чтобы получать сообщения от серверов Telegram воспользуемся поллингом (polling. to poll — опрашивать) — постоянным опросом сервера на наличие новых обновлений. Для этого дописываем в bot.py следующее:
if __name__ == '__main__': executor.start_polling(dp)
from aiogram import Bot, types from aiogram.dispatcher import Dispatcher from aiogram.utils import executor from config import TOKEN bot = Bot(token=TOKEN) dp = Dispatcher(bot) @dp.message_handler(commands=['start']) async def process_start_command(message: types.Message): await message.reply("Привет!\nНапиши мне что-нибудь!") @dp.message_handler(commands=['help']) async def process_help_command(message: types.Message): await message.reply("Напиши мне что-нибудь, и я отпрпавлю этот текст тебе в ответ!") @dp.message_handler() async def echo_message(msg: types.Message): await bot.send_message(msg.from_user.id, msg.text) if __name__ == '__main__': executor.start_polling(dp)
Осталось запустить программу. Для этого в командной строке переходим в директорию проекта и пишем
Теперь можно написать нашему боту:
Делаем Telegram бота с Админ-панелью и многими другими плюшками. Часть 2
Прошлая статья оказалась провальной, именно поэтому хочу улучшить ситуацию путем написания продолжения. Ну буду отвлекаться на самые простые вещи, приступим!
Ну для начала, если вы из прошлой статьи, установите PyCharm. Думаю с установкой сложностей не возникнет, во всяком случае я на это надеюсь.
Открываем PyCharm, создаем файл main.py и начинаем писать.
from aiogram import Bot, Dispatcher, executor, types from aiogram.contrib.fsm_storage.memory import MemoryStorage from aiogram.dispatcher import FSMContext from aiogram.dispatcher.filters.state import State, StatesGroup from aiogram.types import Message import logging import sqlite3
API_TOKEN = 'ТОКЕН' ADMIN = ваш user-id. Узнать можно тут @getmyid_bot kb = types.ReplyKeyboardMarkup(resize_keyboard=True) kb.add(types.InlineKeyboardButton(text="Рассылка")) kb.add(types.InlineKeyboardButton(text="Добавить в ЧС")) kb.add(types.InlineKeyboardButton(text="Убрать из ЧС")) kb.add(types.InlineKeyboardButton(text="Статистика"))
logging.basicConfig(level=logging.INFO) storage = MemoryStorage() bot = Bot(token=API_TOKEN) dp = Dispatcher(bot, storage=storage)
conn = sqlite3.connect('db.db') cur = conn.cursor() cur.execute("""CREATE TABLE IF NOT EXISTS users(user_id INTEGER, block INTEGER);""") conn.commit()
class dialog(StatesGroup): spam = State() blacklist = State() whitelist = State()
Это первые приготовления, теперь мы готовы начинать писать основную логику
@dp.message_handler(commands=['start']) async def start(message: Message): cur = conn.cursor() cur.execute(f"SELECT block FROM users WHERE user_id = ") result = cur.fetchone() if message.from_user.id == ADMIN: await message.answer('Добро пожаловать в Админ-Панель! Выберите действие на клавиатуре', reply_markup=kb) else: if result is None: cur = conn.cursor() cur.execute(f'''SELECT * FROM users WHERE (user_id="")''') entry = cur.fetchone() if entry is None: cur.execute(f'''INSERT INTO users VALUES ('', '0')''') conn.commit() await message.answer('Привет') else: await message.answer('Ты был заблокирован!')
Тут мы добавляем три кнопки в админ-панель
Давайте напишем функцию обработки кнопки «Рассылка»
Теперь давайте обработаем кнопку «Рассылка»
@dp.message_handler(content_types=['text'], text='Рассылка') async def spam(message: Message): await dialog.spam.set() await message.answer('Напиши текст рассылки')
Но тут мы только спрашиваем у админа что за текст рассылки
Теперь давайте обработаем этот текст и отправим его пользователям
@dp.message_handler(state=dialog.spam) async def start_spam(message: Message, state: FSMContext): if message.text == 'Назад': await message.answer('Главное меню', reply_markup=kb) await state.finish() else: cur = conn.cursor() cur.execute(f'''SELECT user_id FROM users''') spam_base = cur.fetchall() for z in range(len(spam_base)): await bot.send_message(spam_base[z][0], message.text) await message.answer('Рассылка завершена', reply_markup=kb) await state.finish()
Тут мы получаем пользователей из Базы и отправляем каждому сообщение
Теперь давайте сделаем добавление пользователей в ЧС
Сейчас мы будем обрабатывать кнопку «Добавить в ЧС»
@dp.message_handler(content_types=['text'], text='Добавить в ЧС') async def hanadler(message: types.Message, state: FSMContext): if message.chat.id == ADMIN: keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True) keyboard.add(types.InlineKeyboardButton(text="Назад")) await message.answer('Введите id пользователя, которого нужно заблокировать.\nДля отмены нажмите кнопку ниже', reply_markup=keyboard) await dialog.blacklist.set()
Но опять же, сейчас бот ничего не сделает с полученным ID. Давайте будем банить пользователей)
@dp.message_handler(state=dialog.blacklist) async def proce(message: types.Message, state: FSMContext): if message.text == 'Назад': await message.answer('Отмена! Возвращаю назад.', reply_markup=kb) await state.finish() else: if message.text.isdigit(): cur = conn.cursor() cur.execute(f"SELECT block FROM users WHERE user_id = ") result = cur.fetchall() if len(result) == 0: await message.answer('Такой пользователь не найден в базе данных.', reply_markup=kb) await state.finish() else: a = result[0] if 0: cur.execute(f"UPDATE users SET block = 1 WHERE user_id = ") conn.commit() await message.answer('Пользователь успешно добавлен в ЧС.', reply_markup=kb) await state.finish() await bot.send_message(message.text, 'Ты был забанен Администрацией') else: await message.answer('Данный пользователь уже получил бан', reply_markup=kb) await state.finish() else: await message.answer('Ты вводишь буквы. \n\nВведи ID')
Вот теперь, после того как Вы отправите ему ID пользователя, он проверить его, и если нашел этого пользователя в Базе не забаненый, то банит! В остальных случаях возвращает в главное меню
Теперь давайте будем Удалять пользователей из ЧС
Для начала, по стандарту, обработаем кнопку
@dp.message_handler(content_types=['text'], text='Убрать из ЧС') async def hfandler(message: types.Message, state: FSMContext): cur = conn.cursor() cur.execute(f"SELECT block FROM users WHERE user_id = ") result = cur.fetchone() if result is None: if message.chat.id == ADMIN: keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True) keyboard.add(types.InlineKeyboardButton(text="Назад")) await message.answer('Введите id пользователя, которого нужно разблокировать.\nДля отмены нажмите кнопку ниже', reply_markup=keyboard) await dialog.whitelist.set()
И снова бот ничего не делает, сейчас исправим это!
@dp.message_handler(state=dialog.whitelist) async def proc(message: types.Message, state: FSMContext): if message.text == 'Отмена': await message.answer('Отмена! Возвращаю назад.', reply_markup=kb) await state.finish() else: if message.text.isdigit(): cur = conn.cursor() cur.execute(f"SELECT block FROM users WHERE user_id = ") result = cur.fetchall() conn.commit() if len(result) == 0: await message.answer('Такой пользователь не найден в базе данных.', reply_markup=kb) await state.finish() else: a = result[0] if 1: cur = conn.cursor() cur.execute(f"UPDATE users SET block = 0 WHERE user_id = ") conn.commit() await message.answer('Пользователь успешно разбанен.', reply_markup=kb) await state.finish() await bot.send_message(message.text, 'Вы были разблокированы администрацией.') else: await message.answer('Данный пользователь не получал бан.', reply_markup=kb) await state.finish() else: await message.answer('Ты вводишь буквы. \n\nВведи ID')
Теперь добавим статистику для нашего бота
В отличии от других функций, эта будет самая простая.
Тут мы будем получать количество пользователей в боте, не активных, ни каких других, просто тех кто зашел хоть раз в бот
@dp.message_handler(content_types=['text'], text='Статистика') async def hfandler(message: types.Message, state: FSMContext): cur = conn.cursor() cur.execute('''select * from users''') results = cur.fetchall() await message.answer(f'Людей которые когда либо заходили в бота: ')
Теперь у вас есть еще и статистика для бота
В конце файла мы должны добавить две строчки
if __name__ == '__main__': executor.start_polling(dp, skip_updates=True)
Теперь просто запускаем и идем проверять!
Понимаю функционал не большой, не то что говорилось в названии, но я принимаю предложения что же добавить еще! В будущем ваще предложения я скорее всего реализую, и буду добавлять в эту статью, либо в новую!
Как обычно, я доступен в ТГ: @derkown