Discord 커뮤니티를 운영하다 보면 반복적인 관리 작업이나 자동화가 필요한 순간이 많다. 하지만 대부분의 개발자들은 봇을 만들어야 한다는 건 알면서도 어디서부터 시작해야 할지, 정확히 어떤 라이브러리를 써야 할지 모른 채 방황한다. 이번에는 Python의 discord.py 라이브러리를 이용해 Discord 봇을 처음부터 끝까지 만드는 방법을 완벽하게 정리했다. 환경 설정, 기본 개념, 실제 명령어 구현, 흔한 실수까지 한 번에 해결할 수 있다.
Discord 봇이 작동하는 기본 흐름은 이렇다:
1. Discord 공식 사이트에서 봇을 등록하고 토큰을 받는다
2. Python 코드에서 그 토큰을 이용해 봇 클라이언트를 만든다
3. 봇이 받을 이벤트(메시지, 반응, 명령어 등)를 정의한다
4. 봇을 실행하면 Discord 서버에 접속해서 대기한다
먼저 Discord Developer Portal에 접속해서 새 애플리케이션을 만든다. 애플리케이션 이름을 정하고 "Bot" 탭에서 "Add Bot" 버튼을 클릭한다. 그러면 봇 토큰이 생성되는데, 이 토큰은 절대 공개하면 안 된다(깃허브에 올리거나 SNS에 공유하지 말 것). 토큰을 안전하게 저장해두자.
Python 3.8 이상이 설치되어 있어야 한다. 터미널에서 아래 명령어로 discord.py를 설치한다.
pip install discord.py
버전 확인:
pip show discord.py
import discord
from discord.ext import commands
bot = commands.Bot(command_prefix='!')
@bot.event
async def on_ready():
print(f'{bot.user} has connected to Discord!')
bot.run('YOUR_BOT_TOKEN_HERE') # ✗ 토큰이 코드에 노출됨
왜 안 되는가: 토큰이 코드에 직접 적혀 있으면 깃허브에 올릴 때나 코드를 공유할 때 토큰이 노출되기 쉽다. 누군가 이 토큰을 얻으면 당신의 봇을 마음대로 조종할 수 있다.
먼저 프로젝트 폴더 루트에 .env 파일을 만들고 토큰을 저장한다:
DISCORD_TOKEN=your_bot_token_here
그 다음 python-dotenv를 설치한다:
pip install python-dotenv
이제 코드에서 환경변수를 읽는다:
import discord
from discord.ext import commands
import os
from dotenv import load_dotenv
load_dotenv()
token = os.getenv('DISCORD_TOKEN')
bot = commands.Bot(command_prefix='!')
@bot.event
async def on_ready():
print(f'{bot.user} has connected to Discord!')
bot.run(token) # ✓ 토큰이 환경변수에서 읽혀서 안전함
왜 이게 맞는가: 토큰이 .env 파일에 저장되고, .env는 .gitignore에 추가하면 깃허브에 올라가지 않는다. 코드에는 토큰을 읽는 로직만 남아서 공유해도 안전하다.
Discord 봇이 처리할 명령어를 정의한다. 사용자가 "!ping"이라고 치면 "Pong!"이라고 답하는 간단한 예제다:
import discord
from discord.ext import commands
import os
from dotenv import load_dotenv
load_dotenv()
token = os.getenv('DISCORD_TOKEN')
bot = commands.Bot(command_prefix='!')
@bot.event
async def on_ready():
print(f'Logged in as {bot.user}')
await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name="!help"))
@bot.command(name='ping')
async def ping(ctx):
await ctx.send(f'Pong! {round(bot.latency * 1000)}ms')
@bot.command(name='hello')
async def hello(ctx):
await ctx.send(f'Hello {ctx.author.name}!')
bot.run(token)
이 코드를 실행하면 봇이 Discord 서버에 접속한다. "!ping"이라고 치면 "Pong! XXms" 형태로 응답하고, "!hello"라고 치면 "Hello [사용자이름]!"이라고 응답한다.
사용자가 입력한 값을 받아서 처리하려면 매개변수를 받아야 한다:
@bot.command(name='greet')
async def greet(ctx, name):
await ctx.send(f'Hello {name}! Nice to meet you.')
# 사용법: !greet Alice
# 결과: Hello Alice! Nice to meet you.
명령어가 아닌 모든 메시지에 반응하려면 on_message 이벤트를 사용한다:
@bot.event
async def on_message(message):
# 봇 자신의 메시지는 무시
if message.author == bot.user:
return
# 특정 단어가 포함되면 반응
if 'hello' in message.content.lower():
await message.channel.send(f'Hi {message.author.name}!')
# 명령어도 처리하기 위해 이 줄은 반드시 마지막에
await bot.process_commands(message)
| 문제 | 원인 | 해결법 |
|---|---|---|
| "Command raised an exception: MissingRequiredArgument" | 명령어에 필요한 매개변수가 없음 | @bot.command 아래 함수에 필요한 매개변수를 모두 정의하기 |
| "The application did not respond" | async 함수가 너무 오래 걸림 | 시간이 오래 걸리는 작업은 asyncio.create_task()로 백그라운드 실행 |
| 봇이 메시지에 반응하지 않음 | on_message에서 process_commands 호출 안 함 | on_message 맨 마지막에 await bot.process_commands(message) 추가 |
| "Forbidden (status code: 403)" | 봇이 특정 채널에 메시지를 보낼 권한 없음 | Discord 서버 설정에서 봇 역할에 필요한 권한 부여 |
새로운 사용자가 서버에 들어오면 자동으로 환영 메시지를 보내는 봇을 만들어보자:
import discord
from discord.ext import commands
import os
from dotenv import load_dotenv
load_dotenv()
token = os.getenv('DISCORD_TOKEN')
bot = commands.Bot(command_prefix='!')
@bot.event
async def on_ready():
print(f'Bot is ready! Logged in as {bot.user}')
@bot.event
async def on_member_join(member):
"""새 멤버가 서버에 들어왔을 때"""
channel = discord.utils.get(member.guild.channels, name='general')
if channel:
embed = discord.Embed(
title=f'Welcome {member.name}!',
description=f'{member.mention}님이 서버에 입장했습니다.',
color=discord.Color.green()
)
embed.set_thumbnail(url=member.avatar.url)
await channel.send(embed=embed)
@bot.command(name='userinfo')
async def userinfo(ctx, member: discord.Member = None):
"""사용자 정보 출력"""
member = member or ctx.author
embed = discord.Embed(
title=f'{member.name}의 정보',
color=discord.Color.blue()
)
embed.add_field(name='ID', value=member.id, inline=False)
embed.add_field(name='가입일', value=member.created_at.strftime('%Y-%m-%d'), inline=False)
embed.add_field(name='서버 가입', value=member.joined_at.strftime('%Y-%m-%d'), inline=False)
embed.set_thumbnail(url=member.avatar.url)
await ctx.send(embed=embed)
bot.run(token)
이 코드는 1) 새 멤버가 들어오면 일반 채널에 환영 메시지를 임베드 형식으로 보내고, 2) "!userinfo [사용자명]" 명령어로 해당 사용자의 정보를 조회할 수 있게 한다.
Discord 봇은 결국 메시지를 받고 처리하는 프로그램일 뿐이다. 토큰을 안전하게 관리하고, async/await 문법을 이해하고, 이벤트 시스템을 활용하면 원하는 기능을 거의 모두 만들 수 있다는 걸 잊지 말자. 작은 명령어 하나에서 시작해서 점진적으로 기능을 추가하면, 서버 관리부터 게임 봇까지 만들 수 있다. 이 글의 '환경변수 설정' 부분을 참고해 토큰을 안전하게 보관하고, '실전 예제' 코드를 직접 실행해본 뒤 자신의 서버에 맞게 커스터마이징하면, 완전히 자동화된 Discord 봇을 갖출 수 있을 것이다.