Developing a Telegram Bot in Python

To create a Telegram bot in Python, there are two main libraries: telebot and aiogram. I will be using the first one.

In Telegram, you need to find the official bot called BotFather. Click “Start,” and a wall of text will appear; we need the command /newbot. We will be asked to come up with a name for our bot, which can be anything. Next, we need to come up with a username. This is a bit more complicated: it must be a unique name that ends with “bot.” After that, we will be congratulated, given the bot’s address, offered to add a description, and set an avatar, but the most important part is the token. It allows us to connect to the bot, program it, and is essentially the most crucial part.

We need to create a virtual environment, activate it, and install our library.

shell

python3 -m venv venv
source venv/bin/activate
pip install pyTelegramBotAPI

We import the telebot library, create an instance of the TeleBot class, and pass our token as a string to the token parameter. I recommend storing the token in a separate file, for example, creating a file called config.py and writing it there, then simply importing it into the main file.

python

import telebot
from config import TOKEN

bot = telebot.TeleBot(TOKEN)


@bot.message_handler(commands=["start"])
def hello(message):
    bot.send_message(message.chat.id, "Hello")


bot.polling(non_stop=True)

We use the decorator @bot.message_handler (not to be confused with @bot.message_handlers) and pass an array (mandatory) of commands that the function will respond to in the commands parameter. The commands can be anything, so you can do something like: @bot.message_handler(commands=["start", "test", "help", "how"]), etc. If this parameter is not specified, the function will trigger on any text. Next comes our function. The name can be anything, but it must always accept the message parameter, which contains all the data about the message. Finally, we send the message. The send_message method takes the chat ID as the first parameter and the text as the second. It can only send text data; other types of data require different methods. The line bot.polling(non_stop=True) starts the bot itself. non_stop=True means that as long as the code is running, the bot is running too. If we run the code now and go to the chat with our bot and type /start, we will receive Hello.

python

import telebot
from config import TOKEN

bot = telebot.TeleBot(TOKEN)


@bot.message_handler(commands=["start"])
def hello(message):
    print(message)


bot.polling(non_stop=True)

If we simply print the message parameter, it will look something like this:

json

{
  'content_type': 'text',
  'id': 8,
  'message_id': 8,
  'from_user': {
    'id': 0,
    'is_bot': False,
    'first_name': '_',
    'username': '_',
    'last_name': '_',
    'language_code': 'ru',
    'can_join_groups': None,
    'can_read_all_group_messages': None,
    'supports_inline_queries': None,
    'is_premium': None,
    'added_to_attachment_menu': None,
    'can_connect_to_business': None
  },
  'date': _,
  'chat': {
    'id': _,
    'type': 'private',
    'title': None,
    'username': '_',
    'first_name': '_',
    'last_name': '_',
    'is_forum': None,
    'max_reaction_count': None,
    'photo': None,
    'bio': None,
    'join_to_send_messages': None,
    'join_by_request': None,
    'has_private_forwards': None,
    'has_restricted_voice_and_video_messages': None,
    'description': None,
    'invite_link': None,
    'pinned_message': None,
    'permissions': None,
    'slow_mode_delay': None,
    'message_auto_delete_time': None,
    'has_protected_content': None,
    'sticker_set_name': None,
    'can_set_sticker_set': None,
    'linked_chat_id': None,
    'location': None,
    'active_usernames': None,
    'emoji_status_custom_emoji_id': None,
    'has_hidden_members': None,
    'has_aggressive_anti_spam_enabled': None,
    'emoji_status_expiration_date': None,
    'available_reactions': None,
    'accent_color_id': None,
    'background_custom_emoji_id': None,
    'profile_accent_color_id': None,
    'profile_background_custom_emoji_id': None,
    'has_visible_history': None,
    'unrestrict_boost_count': None,
    'custom_emoji_sticker_set_name': None,
    'business_intro': None,
    'business_location': None,
    'business_opening_hours': None,
    'personal_chat': None,
    'birthdate': None
  },
  'sender_chat': None,
  'is_automatic_forward': None,
  'reply_to_message': None,
  'via_bot': None,
  'edit_date': None,
  'has_protected_content': None,
  'media_group_id': None,
  'author_signature': None,
  'text': '/kak',
  'entities': [
    <telebot.types.MessageEntity
    object
    at
    0x7f7d0dbd1390>
  ],
  'caption_entities': None,
  'audio': None,
  'document': None,
  'photo': None,
  'sticker': None,
  'video': None,
  'video_note': None,
  'voice': None,
  'caption': None,
  'contact': None,
  'location': None,
  'venue': None,
  'animation': None,
  'dice': None,
  'new_chat_members': None,
  'left_chat_member': None,
  'new_chat_title': None,
  'new_chat_photo': None,
  'delete_chat_photo': None,
  'group_chat_created': None,
  'supergroup_chat_created': None,
  'channel_chat_created': None,
  'migrate_to_chat_id': None,
  'migrate_from_chat_id': None,
  'pinned_message': None,
  'invoice': None,
  'successful_payment': None,
  'connected_website': None,
  'reply_markup': None,
  'message_thread_id': None,
  'is_topic_message': None,
  'chat_background_set': None,
  'forum_topic_created': None,
  'forum_topic_closed': None,
  'forum_topic_reopened': None,
  'has_media_spoiler': None,
  'forum_topic_edited': None,
  'general_forum_topic_hidden': None,
  'general_forum_topic_unhidden': None,
  'write_access_allowed': None,
  'users_shared': None,
  'chat_shared': None,
  'story': None,
  'external_reply': None,
  'quote': None,
  'link_preview_options': None,
  'giveaway_created': None,
  'giveaway': None,
  'giveaway_winners': None,
  'giveaway_completed': None,
  'forward_origin': None,
  'boost_added': None,
  'sender_boost_count': None,
  'reply_to_story': None,
  'sender_business_bot': None,
  'business_connection_id': None,
  'is_from_offline': None,
  'effect_id': None,
  'show_caption_above_media': None,
  'json': {
    'message_id': 8,
    'from': {
      'id': _,
      'is_bot': False,
      'first_name': '_',
      'last_name': '_',
      'username': '_',
      'language_code': 'ru'
    },
    'chat': {
      'id': _,
      'first_name': '_',
      'last_name': '_',
      'username': '_',
      'type': 'private'
    },
    'date': _,
    'text': '/kak',
    'entities': [
      {
        'offset': 0,
        'length': 4,
        'type': 'bot_command'
      }
    ]
  }
}

*This piece of code has been formatted for better readability.

Here, all the information about the message is collected. There is the type, ID, and the text of the message, etc. There is also some data about the sender, such as their name, ID, and the language they are using. And this is not a dictionary, as it might seem, but an instance of the Message class. You can verify this by printing its type.

python

import telebot
from config import TOKEN

bot = telebot.TeleBot(TOKEN)


@bot.message_handler(commands=["start"])
def hello(message):
    print(type(message))
    # <class 'telebot.types.Message'>


bot.polling(non_stop=True)

Accordingly, you should access it not like this: message.get(“chat”).get(“id”), but like this: message.chat.id. Knowing this, we can write a bot that greets us by name.

python

import telebot
from config import TOKEN

bot = telebot.TeleBot(TOKEN)


@bot.message_handler(commands=["start"])
def hello(message):
    bot.send_message(message.chat.id, f"Hello, {message.from_user.first_name}")


bot.polling(non_stop=True)

This type of button is attached directly to the message itself. When the button is pressed, some event can be triggered.

python

import telebot
from telebot import types
from config import TOKEN

bot = telebot.TeleBot(TOKEN)


@bot.message_handler(commands=["start"])
def start(message):
    markup = types.InlineKeyboardMarkup()
    button = types.InlineKeyboardButton(text="Our Website", url="https://it-teh.com/ru/")
    markup.add(button)
    bot.send_message(message.chat.id, text=f"Hello, {message.from_user.first_name}", reply_markup=markup)


bot.polling(non_stop=True)

Here, I create an instance of the InlineKeyboardMarkup class and name it markup. This is something like a framework to which the button will be attached. Next, I create the button itself. Here, I use the InlineKeyboardButton class. The first parameter is the text that will be displayed on the button, and the second is the event that occurs after pressing it. In this case, it is a link to the website. Then, I add the button to our ‘framework’ using the add() method. When sending the message, it is necessary to specify the reply_markup parameter and pass our markup to it.

Reply buttons differ from Inline buttons in that they are attached below the user’s keyboard.

Another feature of these buttons is that when pressed, the text of the button is sent to the chat. Essentially, this is a template with ready-made response options.

python

import telebot
from telebot import types
from config import TOKEN

bot = telebot.TeleBot(TOKEN)


@bot.message_handler(commands=["start"])
def start(message):
    markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
    button1 = types.KeyboardButton("Our Website")
    button2 = types.KeyboardButton("Hello")
    markup.add(button1, button2)
    bot.send_message(message.chat.id,
                     text=f"Hello, {message.from_user.first_name}",
                     reply_markup=markup)


@bot.message_handler(content_types=["text"])
def text(m):
    if m.text == "Our Website":
        bot.send_message(m.chat.id, text="Our website: https://it-teh.com/ru")
    if m.text == "Hello":
        bot.send_message(m.chat.id, text="Hello again, "
                                         f"{m.from_user.first_name}")

The method of creating these buttons is very similar to the previous one. An instance of the ReplyKeyboardMarkup class is created. When creating it, it is advisable to specify the resize_keyboard=True parameter so that the button is not too large.

Related Content