Creating a minimal Discord bot in python

Ivan Ooi
Computing and Commerce Association
8 min readAug 27, 2020

In this tutorial, I’ll teach you how to code a Discord bot in python!

Who needs stock photos?

Introduction

As of 2020, I am a third year student doing Software Engineering and Computer Science at Monash University in Clayton, and the Vice Director of IT for CCA. I’ve been coding since I was in year 9, and it was in high school when I fell in love with coding and problem solving in general. I consider myself to have learned coding with C#, in a game development class in year 10, and continued with that language in year 11 for a Software Development subject. I then picked up Python in year 12 for a Computer Science subject, and have since been using Python, Java, and JavaScript throughout uni.

That’s enough about me, so let’s keep going with the Discord bot. Chatbots are pretty simple in nature — you input a command and it gives an output. It’s not different to any function in Python or any other language, but it’s much more interactive, and it doesn’t require the person using the chatbot to have installed any prerequisite software. This draws parallels to a web app: as long as you have a browser(Discord app), you can access the web app(Discord chatbot). However, the person creating the software obviously does need some software installed. For this tutorial, I’ll be going through how to make a Discord bot with discord.py on Windows, as I’m not familiar enough to be teaching anything on Mac or Linux. If SSL handshakes fail, try running sudo “./Install Certificates.command” in the Python folder.

You’ll need:

- An IDE to write python code in

- Python 3.5 or higher, according to discord.py documentation

- discord.py

- A Discord account

-A server to test your bot in (you can just make your own)

Step 0. Installing discord.py

This first section is all about installing discord.py. Literally all you have to do is go to your command prompt and type: “pip install discord.py” and that should handle everything. I’m not sure what the equivalent is for other platforms, but the rest of the tutorial should be platform generic, but no guarantees, I’m only working on Windows.

Step 1. Creating a bot account on Discord

Before we can start coding, we have to create an actual bot profile for the bot we want to make. Head over to this link: https://discord.com/developers/applications, and make sure you have logged in, and hit “New Application” in the top right. Type in a name and hit the create button, because that’s the whole point of this tutorial! You should now be sitting in front of a screen with your new App.

Actually, there’s a lot more you can do with your app on Discord than just make a bot, but I’ll leave that for you to learn more. For now, scroll to the Bot tab on the sidebar and hit the “Add Bot” button. Congrats! Your app now has a bot! This screen is pretty self-explanatory, the important bit here is your token. We’ll need that later, but first we need to add the bot to our server. Click the OAuth2 tab on the left, right above the Bot tab, and click the “bot” checkbox under scopes, then copy that URL into your browser!

I’ve taken some screenshots to make it super clear.

Here is what the OAuth2 tab looks like
This is what shows up after you paste the link that you generated into your browser
And now, its alive! Well, it exists. We’ll make it come to life in the next section!!

Step 2. Running the bot

Here’s where we finally get to boot up our IDE and go to work. I use PyCharm, just because it has git integration, in-built plugin support and it is super easy to change the background image(most important feature). But that’s just me. Taking the driver code from: https://github.com/Rapptz/discord.py, we can see that there are two examples. There are obvious implications from both, and you are free to experiment with them on your own, but we are running with the second example, using discord.ext’s commands library.

The documentation for that is found here: https://discordpy.readthedocs.io/en/latest/ext/commands/index.html, but its not like we read documentation before actually starting development around here (don’t be like me). At this point, you should set up your version control, etc, if you want but for brevity’s sake I’ll assume you know how to do that. If you don’t, don’t worry. I’ll probably make a tutorial that is just as unprofessional as this one about that. There will also probably a joke from the future me around this area in brackets and a fancy font.

from discord.ext import commandstoken = "please_keep_your_token_secret!"

bot = commands.Bot(command_prefix='>')
bot.run(token)
Its ALIVE!!!!

The driver code for making the bot run, and literally nothing else, is as above. First, we need to import the commands library. Also, remember when I said that the bot token is important? A unique token is needed to run a bot. This means that anyone with your token can start your bot and say whatever they want, so make sure you keep it secret. Next, we specify the command prefix (you can set it to whatever you like, so it doesn’t conflict with other bots) and finally we call bot.run()! Obviously next, we need to add actual code so it actually responds!

Step 3. Adding basic commands to the bot

All right, this is where it gets a bit spicy! To continue with the driver code, we have:

@bot.event
async def on_ready():
print('Logged on as', bot.user)

These lines of code are fired when your bot first comes online — and a convenient way for me to show you the difference between events and commands. Basically, event is a function decorator, which are objects that are called to modify the function. discord.py takes care of all of this for us, so we don’t have to worry too much about this, but an event is predefined in the documentation. Here, when the bot has become ready, it will send a message to the python command line(not a discord channel!). The relevant documentation is here: https://discordpy.readthedocs.io/en/latest/api.html?highlight=event#discord-api-events

Next, we have our FIRST COMMAND! How exciting!

@bot.command()
async def ping(ctx):
await ctx.send('pong')

This is what we have all been waiting for, what we think of when we think chatbots! These lines pretty much what you would expect, you use the “async def” keyword to define the function as a coroutine. I’ll link the relevant documentation later, when we talk about await. The name of the function corresponds to the command that you would type to run the command. In this case, in discord you would type “>ping”, and the bot would respond with “pong”, like so!

There’s only one right answer to ping

To continue, the parameter “ctx” is the Context object of the message. The commands extension allows us to simply call Context.send() to send a message after a command is called. For more detail, check this documentation: https://discordpy.readthedocs.io/en/latest/ext/commands/commands.html

Step 4. Learning the foundations of discord.py

Here is where we learn about the boring stuff — but its what you need to make your bot run. Specifically, we need to talk about the command decorator, as it is very commonly used — every command needs this. Here, we use the await keyword, which is basically the other half of the asyncio library for python, which discord.py uses. The relevant documentation is: https://docs.python.org/3/library/asyncio-task.html

I’m not going to pretend like I know everything about coroutines — but from my understanding they are functions that you can exit and enter at many different points using “await” and “async” keywords, and asynchronous just means the function is being run separately from the main thread. Threading is also a very useful technique to work with(but probably too big to write a guide on). So here, we use the await keyword before the Context.send() method to make it asynchronous. The send() method can actually also be called from the TextChannel object, if you prefer to separate things more logically (you can get the channel from the Context, and then call send() from the channel).

ctx.channel.send(“pong”) # an alternative way to send messages

Step 5 and beyond: Adding more functionality

That’s the end of the rundown of the barebones bot, you now know how to write a bot that “pongs” as soon as you ping it! Now you can write *literally* whatever you want instead of pong, to solve some kind of issue that you have in your Discord server, by implementing a solution in Python! For example, for the official CCA bot, I wrote a command that scrapes the text on the events page of the website and sends it as a message, so whenever you type “!events”, so you can just type the command rather than navigating over to the website. I’ll explain it if you are interested.

import requests
from bs4 import BeautifulSoup
@client.command()
async def events(ctx):
"""
This events command works by reading the webpage of the events website, so we only need to update one place!
"""
# code is kind of messy right now
# requires requests and BeautifulSoup4
url = "https://www.ccamonash.com.au/events"

response = requests.get(url)

# HTTP Response 200 means everything is OK
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')

div = soup.findAll("div", {"class": "col sqs-col-6 span-6"})

string = ""
for i in range(1, len(div)):
for j in div[i].findAll(["h2", "p"]):
if str(j)[0:3] == "<h2":
string += "\n"
string += j.text + "\n"
await ctx.send(string)
else:
await ctx.send("Something went wrong - Try again!")

This monstrous block of code is what powers the !events command on our very own CCA bot. To be honest, there isn’t a limit to what you could do with chatbots. Literally anything you could regularly do in Python, you could hook up a bot to do for you! This is just an example of what you could do that might be helpful in a timely manner(the events page gets updated appropriately). First, we get the content of the events page. Next, we parse the html data that we got from the website. Then, we use BeautifulSoup to look for all the divs where the information is written, and we just construct a string containing it! There was a bit of fiddling with the implementation to get the right data but that’s to be expected.

The result of the code

Conclusion

Thats basically all from me. I just want to stress that the important part for implementing the software solutions is all about reading documentation(I know, I know). It is very dry, and many times isn’t very clear, but is the key to coding in general, not just for making a bot. If you wanted a bot to perform an action, not just in response to a message, but a react or deletion, you could find that in the documentation! Thankfully, I’ve found discord.py’s documentation to be very high quality. I’m sure you can write many more ingenious solutions to modern day problems, and now you are equipped to do it!

All links mentioned in the article:

Barebones code: https://github.com/Rapptz/discord.py

discord.py commands: https://discordpy.readthedocs.io/en/latest/ext/commands/commands.html

discord.py events: https://discordpy.readthedocs.io/en/latest/api.html?highlight=event#discord-api-events

asyncio: https://docs.python.org/3/library/asyncio-task.html

--

--

Ivan Ooi
Computing and Commerce Association

Software Engineering and Computer Science student | Persistent problem solver