Create and Deploy a Telegram Bot with Python

Published May 09, 2017
Create and Deploy a Telegram Bot with Python

On the surface, Telegram is just another messaging app. The app promotes itself as secure, fast, ad-free, etc. However, there is one feature that sets it apart from similar apps: bots! In this tutorial, we’re going to build a very simple bot using Python and deploy it on a Heroku server.

Why Create a Bot?

First, I will discuss what bots are and why you might be interested in creating one. If you already know these things, feel free to skip ahead.

The term “bots” might call to mind those scripted auto-reply “live chat” programs we’ve all seen, but they’re not the same. These guys are amazing little helpers you can use in any chat.
Think of a bot as an automated user account that can do favors for you. For example, let’s say you want to share a YouTube link in a group chat, but you don’t have the link yet.

Without the bot:

  • Open YouTube in your web browser.
  • Search for a video you’d like to share
  • Select “share via..." (and hope your app is listed in YouTube sharing list)
  • Skip the above step and do an old school copy/paste
  • Go back to your messaging app, and finally share the link

Of course, most of us have already gotten used to that method and it works fine. However...

With the bot:

  • You’re in the process of communication in your messaging app.
  • Without leaving your messaging app, type in @vid followed by the title of the video you’d like to share
  • Press return

Obviously, the second way is more user-friendly and less time-consuming, and this is only one example of bot capabilities.

Telegram did a great job in allowing users to create their own bots. Let’s look at how to do it. Answering the question why it might be interesting I can say that it’s the easiest way to get the idea of APIs.

How to Create Your First Bot

First, register on Telegram. I recommend using Telegram web client to test the basic concepts.

Open the Telegram app, search for @BotFather and start the chat. Send /newbot and follow the instructions. After completing the initial steps, you’ll get:

That’s all the setup, but at the moment the bot is 100% passive.

Initiate a conversation with your bot by searching its name and clicking on /start. Type in your greeting; this is the first update your bot is going to receive.

If this is your first experience building APIs, you can get the hang of it by using your web browser. Open a new tab in your browser and use the Telegram api URL:

https://api.telegram.org/bot<token>/getUpdates

When you open this URL in your web browser, you make a request to the Telegram server, which then responds in JSON. This response resembles Python dictionary. You should see something like this:

{"ok":true,"result":[{"update_id":523349956,
"message":{"message_id":51,"from":{"id":303262877,"first_name":"YourName"},"chat":{"id":303262877,"first_name":"YourName","type":"private"},"date":1486829360,"text":"Hello"}}]}

If you open the bot’s documentation and check the /sendMessage method section you’ll notice that this method requires two additional parameters: chat_id and text. In a browser search bar you can chain parameters using ? for the first one and & for all subsequent ones. Send message would look like this:

/sendMessage?chat_id=303262877&text=test

Try to get the reply from your bot by substituting chat_id with one you get by calling /getUpdates. In my case it is 303262877. The text parameters are up to you. The request should look like this

https://api.telegram.org/bot<token>/sendMessage?chat_id=303262877&text=Hello

The Almost Coding Part

If you’re on Windows and don’t have Python installed, you can get it here.

It doesn’t matter whether you have version 2.x or 3.x, but I am going to use Python 3.x for the examples.

The next step is to install pip. Python 2.7.9 and above, and Python 3.4 and above include pip already.

If you use macOS/Linux, you may already have it. You can check by using the pip --version command in the terminal.

If you don't have it, you can install pip on Debian-based Linux using the following command

$ sudo apt-get install python-pip.  

The tricky part is that separate versions of Python use their own pip.

On Mac OS you can try instructions from here

On Windows download get-pip.py, open cmd, go to a directory where you saved the file and run the following command —

$ python get-pip.py

If all goes well, that should be the hardest part.

Next, you need to install a requests package using the following command:

$ pip install requests

Next step is optional but it will be of great help. Install PyCharm — it rocks.

The Actual Coding Part

Now that the idea of APIs is clear and we have all the necessary tools, let’s make a Python script that will check for updates and reply with the desired text.

First of all, our bot should check for updates. Our message functions as the most recent update. However, getUpdates will return all the updates for the last 24 hours. Let’s create a small script to get the last update.

import requests

url = "https://api.telegram.org/bot<token>/"


def get_updates_json(request):
    response = requests.get(request + 'getUpdates')
    return response.json()


def last_update(data):
    results = data['result']
    total_updates = len(results) - 1
    return results[total_updates]

The updates dictionary consists of two elements:“ok”, and “results.” We are interested in the “results” part that is a list of all updates our bot has gotten in the last 24 hours.

You can find more information in the requests library here. The core idea is that whenever you need to get, update or delete information on a server, you send a request and get a response.

The next step is to add two more functions. The first one will get the chat_id from the update and the second one will send a message.

def get_chat_id(update):
    chat_id = update['message']['chat']['id']
    return chat_id

def send_mess(chat, text):
    params = {'chat_id': chat, 'text': text}
    response = requests.post(url + 'sendMessage', data=params)
    return response

chat_id = get_chat_id(last_update(get_updates_json(url)))

send_mess(chat_id, 'Your message goes here')

Remember when you chained parameters with "?" and "&"? You can do the same by adding dict as the second optional parameter to the requests get/post function.

The script is ready, but it’s far from perfect. As it stands, you need to run the script each time you want to send a message with bot, but we can make things simpler. To make our bot listen to the server to get updates, we need to start a mainloop. Add from time import sleep on a new line right after import requests.


def main():
    update_id = last_update(get_updates_json(url))['update_id']
    while True:
        if update_id == last_update(get_updates_json(url))['update_id']:
           send_mess(get_chat_id(last_update(get_updates_json(url))), 'test')
           update_id += 1
    sleep(1)       

if __name__ == '__main__':
    main()

Although we have added a "timeout" of one second, the above example should only be used for testing purposes as it uses a short polling. It’s no good for Telegram servers and should be avoided. There are two ways to get the updates with your bot api — long polling or webhook. However, if we check for updates using a getUpdates method without any parameters, short polling will be used.

As we start to use a mainloop in our script, we will need to switch to long polling.

To make our script use a long polling, we need to modify the first function by adding a timeout parameter.

The timeout itself won't make the script check for updates less frequently. The timeout will only work if there are no recent updates. If you want to indicate that certain update has been already seen you need to add an "offset" parameter.

def get_updates_json(request):
    params = {'timeout': 100, 'offset': None}
    response = requests.get(request + 'getUpdates', data=params)
    return response.json()

By now the bot should work alright, but let’s modify the whole code a little bit. It’s a good idea to encapsulate all the functions we have used so far and create a class. So the modified version may look something like this:

import requests
import datetime

class BotHandler:

    def __init__(self, token):
        self.token = token
        self.api_url = "https://api.telegram.org/bot{}/".format(token)

    def get_updates(self, offset=None, timeout=30):
        method = 'getUpdates'
        params = {'timeout': timeout, 'offset': offset}
        resp = requests.get(self.api_url + method, params)
        result_json = resp.json()['result']
        return result_json

    def send_message(self, chat_id, text):
        params = {'chat_id': chat_id, 'text': text}
        method = 'sendMessage'
        resp = requests.post(self.api_url + method, params)
        return resp

    def get_last_update(self):
        get_result = self.get_updates()
        
        if len(get_result) > 0:
            last_update = get_result[-1]
        else:
            last_update = get_result[len(get_result)]

        return last_update

Now the final touch is to declare variables and teach this bot some manners. The idea is to make a bot that will greet you back once a day. Depending on a time of the day the reply will be different. If you want to try this script you need to add import datetime on the next line after import requests, and the following code to your script

greet_bot = BotHandler(token)
greetings = ('hello', 'hi', 'greetings', 'sup')
now = datetime.datetime.now()


def main():
    new_offset = None
    today = now.day
    hour = now.hour

    while True:
        greet_bot.get_updates(new_offset)

        last_update = greet_bot.get_last_update()
                
        last_update_id = last_update['update_id']
        last_chat_text = last_update['message']['text']
        last_chat_id = last_update['message']['chat']['id']
        last_chat_name = last_update['message']['chat']['first_name']

        if last_chat_text.lower() in greetings and today == now.day and 6 <= hour < 12:
            greet_bot.send_message(last_chat_id, 'Good Morning  {}'.format(last_chat_name))
            today += 1

        elif last_chat_text.lower() in greetings and today == now.day and 12 <= hour < 17:
            greet_bot.send_message(last_chat_id, 'Good Afternoon {}'.format(last_chat_name))
            today += 1

        elif last_chat_text.lower() in greetings and today == now.day and 17 <= hour < 23:
            greet_bot.send_message(last_chat_id, 'Good Evening  {}'.format(last_chat_name))
            today += 1

        new_offset = last_update_id + 1

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        exit()

From here there are thousands of different ways to customize your bot. I recommend that you try to send media methods or add “custom” buttons.

Time to Deploy Your Bot!

The final step to make your bot a real bot is to deploy it on a server. Most likely you don’t have your own server and don’t want to purchase one. Well, you don’t have to: At the moment, there are lots of cloud solutions that will host your app for free. I am going to show you how to deploy this little script to Heroku.

First of all, you need a GitHub account and you need to install Git.

Run the following command on Debian-based Linux:

$ sudo apt-get install git-all

Download Git for:

Sign Up for Heroku here

Install virtualenv using the following command -

$ pip install virtualenv

Now you need to organize your files a bit. Create a new folder, open Terminal/CMD and go to your new folder.

Initialize virtualenv in your new folder — type in

$ virtualenv my_env  

The name doesn’t really matter, however it better to keep it descriptive.
Go to my_env folder.

Next, clone your Git repository. Type in the following command:

$ git clone https://github.com/yourprofilename/yourreponame

Put your script in Git clone folder.

Go back to my_env folder, and start virtualenv using the following command:

Windows:

$ scripts\activate.bat

Linux/macOS:

$ source bin/activate

If you activated virtualenv successfully your console prompt should start with (my_env).

Next, go to your cloned repo and once again install Python requests module by typing —

$ pip install requests

Then create a list of dependencies for Heroku. It’s simple, just type in

$ pip freeze > requirements.txt

Create a Procfile. In this file, you’ll provide the instructions for your script. The name should be exactly Procfile and Procfile.windows for Windows. It shouldn’t have .txt or .py or any other extensions. The contents of the file should be the following (change my_bot with name of your script)

web: python my_bot.py

Add __init__.py file in your folder. The file can be empty, but it should be there.

Type in the following series of commands to commit and push changes you made.

$ git init
$ git add .
$ git commit -m ‘short message that describe changes to commit’
$ git push -u https://github.com/yourusername/nameofrepo

Finally, the actual deployment on Heroku. If you have trouble with their web browser dashboard, it’s easy enough to use the Heroku command line interface. I recommend that you use this guide if you face any troubles.

These several steps should be enough to deploy an app. If you’re on Mac or Windows you can download CLI from this step.

If you’re on Ubuntu like I am, use the following commands:

$ sudo add-apt-repository "deb https://cliassets.heroku.com/branches/stable/apt ./"
$ curl -L https://cli-assets.heroku.com/apt/release.key |
$ sudo apt-key add -
$ sudo apt-get update
$ sudo apt-get install heroku     

On my home computer everything was smooth, however on my laptop, I couldn’t accomplish the last step right away. If you face the same problem, check the terminal for tips and missing dependencies.

Follow the next set of commands -

$ heroku login
$ heroku create
$ git push heroku master
$ heroku ps:scale web=1
$ heroku open

From this moment your app should work on a Heroku server. If it’s not working, check the logs using the following command:

$ heroku logs --trail 

You can find error codes here

With a free account you’ll face certain limitations, but you now have everything you need to create a fully functional bot!

This writeup was much inspired by this Codementor Tutorial.


This post was originally published by the author here. This version has been edited for clarity and may appear different from the original post.

Discover and read more posts from Django Stars
get started
Enjoy this post?

Leave a like and comment for Django

6
1