Python으로 디스코드 봇 만들기 - 초보자를 위한 완벽 가이드
디스코드 봇이란?
디스코드 봇은 서버에서 자동화된 작업을 수행하는 프로그램입니다. 음악 재생, 관리 기능, 게임, 알림 등 다양한 용도로 사용됩니다.
Python은 디스코드 봇을 만들기에 가장 인기 있는 언어 중 하나입니다. discord.py 라이브러리 덕분에 초보자도 쉽게 시작할 수 있습니다.
왜 Python으로 디스코드 봇을 만드나요?
Python의 장점
✅ 간결한 문법 - 배우기 쉽고 코드가 읽기 쉽습니다 ✅ 강력한 라이브러리 - discord.py는 기능이 풍부하고 잘 문서화되어 있습니다 ✅ 빠른 개발 - 적은 코드로 많은 기능을 구현할 수 있습니다 ✅ 활발한 커뮤니티 - 문제가 생기면 도움을 쉽게 구할 수 있습니다
사전 준비사항
1. Python 설치
Python 3.8 이상이 필요합니다. python.org에서 다운로드하세요.
# 버전 확인
python --version
# 또는
python3 --version
2. discord.py 설치
pip install discord.py
# 또는
pip3 install discord.py
3. Discord Developer Portal 설정
봇 생성하기
- Discord Developer Portal에 접속
- “New Application” 클릭
- 봇 이름 입력 (예: “MyFirstBot”)
- 왼쪽 메뉴에서 “Bot” 선택
- “Add Bot” 클릭
- “Reset Token”을 클릭하여 토큰 복사 (⚠️ 절대 공유하지 마세요!)
봇 권한 설정
- “OAuth2” > “URL Generator” 선택
- “SCOPES”에서
bot체크 - “BOT PERMISSIONS”에서 필요한 권한 선택:
- Read Messages/View Channels
- Send Messages
- Embed Links
- Attach Files
- Read Message History
- 생성된 URL로 봇을 서버에 초대
첫 번째 봇 만들기
기본 구조
가장 간단한 봇부터 시작해봅시다.
# bot.py
import discord
from discord.ext import commands
# 봇 인스턴스 생성
# intents는 봇이 어떤 이벤트를 받을지 설정
intents = discord.Intents.default()
intents.message_content = True # 메시지 내용 읽기 권한
bot = commands.Bot(command_prefix='!', intents=intents)
# 봇이 준비되었을 때 실행
@bot.event
async def on_ready():
print(f'{bot.user}로 로그인했습니다!')
print(f'봇 ID: {bot.user.id}')
print('------')
# 간단한 명령어: !안녕
@bot.command()
async def 안녕(ctx):
await ctx.send(f'안녕하세요 {ctx.author.mention}님!')
# !핑 명령어 - 봇의 응답 속도 확인
@bot.command()
async def 핑(ctx):
latency = round(bot.latency * 1000) # ms 단위로 변환
await ctx.send(f'🏓 퐁! 레이턴시: {latency}ms')
# 봇 토큰으로 실행
bot.run('YOUR_BOT_TOKEN_HERE')
환경 변수로 토큰 관리 (보안)
토큰을 코드에 직접 넣는 것은 위험합니다. .env 파일을 사용하세요.
1. python-dotenv 설치
pip install python-dotenv
2. .env 파일 생성
# .env
DISCORD_TOKEN=your_actual_bot_token_here
3. .gitignore에 추가
# .gitignore
.env
4. 수정된 bot.py
import discord
from discord.ext import commands
import os
from dotenv import load_dotenv
# .env 파일 로드
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
intents = discord.Intents.default()
intents.message_content = True
bot = commands.Bot(command_prefix='!', intents=intents)
@bot.event
async def on_ready():
print(f'{bot.user}로 로그인했습니다!')
# 봇 실행
bot.run(TOKEN)
실전 기능 구현
1. 환영 메시지 봇
새로운 멤버가 서버에 들어오면 환영 메시지를 보냅니다.
@bot.event
async def on_member_join(member):
# 시스템 채널에 환영 메시지 전송
channel = member.guild.system_channel
if channel is not None:
embed = discord.Embed(
title='🎉 새로운 멤버!',
description=f'{member.mention}님, 환영합니다!',
color=discord.Color.green()
)
embed.set_thumbnail(url=member.avatar.url)
embed.add_field(name='멤버 수', value=f'{member.guild.member_count}명')
await channel.send(embed=embed)
2. 정보 명령어
서버 또는 유저 정보를 보여줍니다.
@bot.command()
async def 서버정보(ctx):
guild = ctx.guild
embed = discord.Embed(
title=f'{guild.name} 정보',
color=discord.Color.blue()
)
embed.set_thumbnail(url=guild.icon.url if guild.icon else None)
embed.add_field(name='서버 ID', value=guild.id, inline=False)
embed.add_field(name='생성일', value=guild.created_at.strftime('%Y-%m-%d'), inline=True)
embed.add_field(name='멤버 수', value=guild.member_count, inline=True)
embed.add_field(name='채널 수', value=len(guild.channels), inline=True)
await ctx.send(embed=embed)
@bot.command()
async def 유저정보(ctx, member: discord.Member = None):
member = member or ctx.author # 멤버 지정 안 하면 자기 자신
embed = discord.Embed(
title=f'{member.name}의 정보',
color=member.color
)
embed.set_thumbnail(url=member.avatar.url)
embed.add_field(name='닉네임', value=member.display_name, inline=True)
embed.add_field(name='ID', value=member.id, inline=True)
embed.add_field(name='가입일', value=member.joined_at.strftime('%Y-%m-%d'), inline=False)
roles = [role.mention for role in member.roles if role.name != '@everyone']
if roles:
embed.add_field(name='역할', value=', '.join(roles), inline=False)
await ctx.send(embed=embed)
3. 관리 명령어
메시지 삭제, 멤버 관리 등의 기능입니다.
@bot.command()
@commands.has_permissions(manage_messages=True)
async def 청소(ctx, amount: int):
"""메시지 삭제 (관리자 전용)"""
if amount < 1 or amount > 100:
await ctx.send('1~100 사이의 숫자를 입력하세요.')
return
deleted = await ctx.channel.purge(limit=amount + 1)
await ctx.send(f'✅ {len(deleted)-1}개의 메시지를 삭제했습니다.', delete_after=5)
@bot.command()
@commands.has_permissions(kick_members=True)
async def 추방(ctx, member: discord.Member, *, reason='사유 없음'):
"""멤버 추방 (관리자 전용)"""
await member.kick(reason=reason)
await ctx.send(f'{member.mention}님을 추방했습니다. 사유: {reason}')
# 권한 없을 때 에러 처리
@청소.error
@추방.error
async def permission_error(ctx, error):
if isinstance(error, commands.MissingPermissions):
await ctx.send('❌ 이 명령어를 사용할 권한이 없습니다.')
4. 재미있는 기능
주사위, 동전 던지기 등의 게임 기능입니다.
import random
@bot.command()
async def 주사위(ctx, dice: str = '1d6'):
"""주사위 굴리기 (예: !주사위 2d20)"""
try:
rolls, sides = map(int, dice.split('d'))
if rolls > 100 or sides > 1000:
await ctx.send('너무 큰 숫자입니다!')
return
results = [random.randint(1, sides) for _ in range(rolls)]
total = sum(results)
embed = discord.Embed(title='🎲 주사위 결과', color=discord.Color.gold())
embed.add_field(name='주사위', value=dice, inline=True)
embed.add_field(name='결과', value=', '.join(map(str, results)), inline=True)
embed.add_field(name='합계', value=total, inline=True)
await ctx.send(embed=embed)
except:
await ctx.send('형식: !주사위 XdY (예: !주사위 2d6)')
@bot.command()
async def 동전(ctx):
"""동전 던지기"""
result = random.choice(['앞면 🪙', '뒷면 🌑'])
await ctx.send(f'동전 결과: **{result}**')
@bot.command()
async def 선택(ctx, *choices: str):
"""여러 선택지 중 하나를 랜덤으로 선택"""
if len(choices) < 2:
await ctx.send('최소 2개 이상의 선택지를 입력하세요.')
return
choice = random.choice(choices)
await ctx.send(f'🎯 선택: **{choice}**')
5. 투표 시스템
간단한 투표 기능입니다.
@bot.command()
async def 투표(ctx, question: str, *options):
"""투표 생성 (최대 10개 옵션)"""
if len(options) > 10:
await ctx.send('옵션은 최대 10개까지 가능합니다.')
return
if len(options) < 2:
await ctx.send('최소 2개의 옵션이 필요합니다.')
return
# 이모지 숫자
emojis = ['1️⃣', '2️⃣', '3️⃣', '4️⃣', '5️⃣', '6️⃣', '7️⃣', '8️⃣', '9️⃣', '🔟']
description = '\n'.join([f'{emojis[i]} {option}' for i, option in enumerate(options)])
embed = discord.Embed(
title=f'📊 투표: {question}',
description=description,
color=discord.Color.blue()
)
embed.set_footer(text=f'투표 생성자: {ctx.author.display_name}')
poll_message = await ctx.send(embed=embed)
# 반응 추가
for i in range(len(options)):
await poll_message.add_reaction(emojis[i])
6. 타이머 및 알림
import asyncio
@bot.command()
async def 타이머(ctx, seconds: int, *, message='시간이 다 됐습니다!'):
"""타이머 설정 (초 단위)"""
if seconds > 3600: # 1시간 제한
await ctx.send('타이머는 최대 1시간(3600초)까지 설정 가능합니다.')
return
await ctx.send(f'⏰ {seconds}초 타이머를 시작합니다.')
await asyncio.sleep(seconds)
await ctx.send(f'{ctx.author.mention} {message}')
Cogs를 사용한 코드 구조화
봇이 커지면 코드를 모듈화하는 것이 좋습니다. Cogs를 사용하면 기능별로 파일을 분리할 수 있습니다.
프로젝트 구조
discord_bot/
├── bot.py # 메인 파일
├── cogs/ # Cogs 폴더
│ ├── fun.py # 재미 기능
│ ├── moderation.py # 관리 기능
│ └── info.py # 정보 기능
├── .env # 환경 변수
└── requirements.txt # 의존성
Cog 예제: fun.py
# cogs/fun.py
import discord
from discord.ext import commands
import random
class Fun(commands.Cog):
"""재미있는 명령어들"""
def __init__(self, bot):
self.bot = bot
@commands.command()
async def 주사위(self, ctx, dice: str = '1d6'):
"""주사위 굴리기"""
try:
rolls, sides = map(int, dice.split('d'))
results = [random.randint(1, sides) for _ in range(rolls)]
await ctx.send(f'🎲 결과: {results} (합계: {sum(results)})')
except:
await ctx.send('형식: !주사위 XdY')
@commands.command()
async def 동전(self, ctx):
"""동전 던지기"""
result = random.choice(['앞면 🪙', '뒷면 🌑'])
await ctx.send(f'결과: **{result}**')
# Cog 로드 함수
async def setup(bot):
await bot.add_cog(Fun(bot))
메인 파일에서 Cogs 로드
# bot.py
import discord
from discord.ext import commands
import os
from dotenv import load_dotenv
import asyncio
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
intents = discord.Intents.default()
intents.message_content = True
bot = commands.Bot(command_prefix='!', intents=intents)
@bot.event
async def on_ready():
print(f'{bot.user}로 로그인했습니다!')
print('------')
# Cogs 로드
async def load_cogs():
for filename in os.listdir('./cogs'):
if filename.endswith('.py'):
cog_name = filename[:-3] # .py 제거
await bot.load_extension(f'cogs.{cog_name}')
print(f'Loaded cog: {cog_name}')
async def main():
async with bot:
await load_cogs()
await bot.start(TOKEN)
# 봇 실행
asyncio.run(main())
에러 처리
봇이 안정적으로 동작하려면 에러 처리가 중요합니다.
@bot.event
async def on_command_error(ctx, error):
"""전역 에러 핸들러"""
if isinstance(error, commands.MissingRequiredArgument):
await ctx.send(f'❌ 필수 인자가 누락되었습니다: `{error.param.name}`')
elif isinstance(error, commands.MissingPermissions):
await ctx.send('❌ 이 명령어를 사용할 권한이 없습니다.')
elif isinstance(error, commands.CommandNotFound):
# 명령어를 찾지 못했을 때는 무시
pass
elif isinstance(error, commands.CommandOnCooldown):
await ctx.send(f'⏳ 쿨다운 중입니다. {error.retry_after:.1f}초 후에 다시 시도하세요.')
else:
print(f'Unhandled error: {error}')
await ctx.send('❌ 명령어 실행 중 오류가 발생했습니다.')
봇 배포하기
옵션 1: 로컬에서 실행
개발 중에는 로컬에서 실행하면 됩니다.
python bot.py
옵션 2: 클라우드 서버 (24/7 운영)
Replit (무료, 간단)
- Replit 가입
- New Repl 생성 (Python)
- 코드 업로드
- Secrets에
DISCORD_TOKEN추가 - Run 버튼 클릭
Railway / Render (무료/유료)
# railway.json / render.yaml
build:
- pip install -r requirements.txt
start:
- python bot.py
DigitalOcean / AWS (유료, 전문적)
Ubuntu 서버에서 실행:
# 의존성 설치
sudo apt update
sudo apt install python3 python3-pip
# 봇 코드 복사
git clone your-repo-url
cd discord_bot
# 패키지 설치
pip3 install -r requirements.txt
# 백그라운드에서 실행 (screen 사용)
screen -S discord_bot
python3 bot.py
# Ctrl+A+D로 detach
requirements.txt 생성
discord.py>=2.0.0
python-dotenv>=0.19.0
봇을 계속 실행하는 방법
systemd 서비스 (Linux)
# /etc/systemd/system/discordbot.service
[Unit]
Description=Discord Bot
After=network.target
[Service]
Type=simple
User=yourusername
WorkingDirectory=/path/to/bot
ExecStart=/usr/bin/python3 /path/to/bot/bot.py
Restart=always
[Install]
WantedBy=multi-user.target
활성화:
sudo systemctl enable discordbot
sudo systemctl start discordbot
sudo systemctl status discordbot
Docker 사용
# Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "bot.py"]
# docker-compose.yml
version: '3.8'
services:
bot:
build: .
restart: always
env_file:
- .env
실행:
docker-compose up -d
모범 사례 (Best Practices)
1. 토큰 보안
- ✅
.env파일 사용 - ✅
.gitignore에.env추가 - ❌ 코드에 토큰 직접 입력 금지
- ❌ 공개 저장소에 토큰 업로드 금지
2. Rate Limiting
Discord API는 요청 제한이 있습니다. 쿨다운을 사용하세요.
from discord.ext import commands
@bot.command()
@commands.cooldown(1, 5, commands.BucketType.user) # 5초당 1회
async def 명령어(ctx):
await ctx.send('쿨다운이 있는 명령어!')
3. 로깅
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('discord')
4. 데이터베이스 사용
지속적인 데이터 저장이 필요하면 데이터베이스를 사용하세요.
import sqlite3
# 간단한 SQLite 예제
conn = sqlite3.connect('bot_data.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
user_id INTEGER PRIMARY KEY,
points INTEGER DEFAULT 0
)
''')
conn.commit()
더 배우기
유용한 리소스
다음 단계
봇을 만들었다면 이런 기능들을 추가해보세요:
- 데이터베이스 연동 - 유저 포인트, 레벨링 시스템
- API 통합 - 날씨, 뉴스, 게임 정보
- 음악 봇 - YouTube, Spotify 연동
- 대시보드 - 웹 인터페이스로 봇 관리
- AI 챗봇 - OpenAI API 연동
마치며
Python으로 디스코드 봇을 만드는 것은 생각보다 쉽습니다. 이 가이드의 코드를 따라하면 기본적인 봇을 만들 수 있고, 여기서부터 자신만의 기능을 추가할 수 있습니다.
핵심 요점
- discord.py는 강력하고 사용하기 쉬운 라이브러리입니다
- 토큰 보안은 매우 중요합니다
- Cogs를 사용하면 코드를 깔끔하게 정리할 수 있습니다
- 에러 처리와 쿨다운으로 안정적인 봇을 만들 수 있습니다
디스코드 봇 개발을 즐기세요! 🤖✨
질문이나 제안이 있다면 댓글로 남겨주세요.