개요
오늘은 파이썬 언어로 텔레그램 봇을 만들고, 다양한 메시지를 보내는 방법에 대해 총정리해 보겠습니다.
텍스트는 물론 이미지, 파일 전송과 특정 시간에 맞춰 주기적으로 메시지를 보내는 방법, 그리고 사용자가 명령어를 입력했을 때 봇이 반응하게 하는 방법까지!
STEP 0: 시작하기 전에!
봇 생성
가장 먼저 텔레그램 봇을 만들고, 파이썬으로 제어하기 위한 API 토큰을 발급받아야 합니다.
1. 텔레그램 앱에서 /newbot 이라고 채팅을 입력하면 봇 채팅방을 개설할 수 있는 단계가 시작됩니다.
2. 봇 채팅방 이름을 지정해줄게요.
3. 봇의 이름을 지정해줍시다!. 중요한 점은 봇의 이름을 지정할 때는 봇 이름 마지막에 _bot
이라고 끝나야 합니다.
4. 이후 봇 채팅방이 개설되고, 다음의 봇 토큰이 생성되었습니다. 해당 토큰은 이번 실습에서만 사용하고 이후 삭제하겠습니다.
5. 마지막으로 생성된 봇 채팅방 검색 후, start
버튼을 클릭하면 됩니다. (본인이 생성한 봇을 정확히 찾도록 합시다.)
라이브러리 설치
이제 python-telegram-bot
라이브러리를 설치해주도록 하겠습니다.
파이썬으로 텔레그램 봇을 가장 편리하게 다룰 수 있는 python-telegram-bot
라이브러리를 설치합니다.
최신 버전을 사용하기 위해 --upgrade 옵션을 추가하는 것이 좋습니다.
pip install python-telegram-bot --upgrade
내 채팅 ID 확인
봇이 나에게 메시지를 보내려면 나의 고유한 채팅 ID를 알아야 합니다.
- 텔레그램에서
@userinfobot
을 검색하고 대화를 시작하세요. - /start를 누르면 바로 자신의 Id를 알려줍니다.
STEP 1: 기본 메시지 전송하기 (텍스트, 이미지, HTML 파일)
가장 기본적인 텍스트, 이미지, 파일 메시지를 보내는 방법입니다.
최신 python-telegram-bot
라이브러리는 파이썬의 asyncio
를 기반으로 동작하므로, 비동기 방식으로 코드를 작성해야 합니다.
1. 텍스트 메시지 전송하기
가장 간단한 텍스트 메시지를 보내는 방법입니다. bot.send_message
함수를 사용합니다.
import asyncio
import telegram
TOKEN = "YOUR_TELEGRAM_BOT_TOKEN"
CHAT_ID = "YOUR_CHAT_ID"
async def send_text():
bot = telegram.Bot(TOKEN)
await bot.send_message(chat_id=CHAT_ID, text="안녕하세요! 파이썬으로 보내는 텍스트 메시지입니다. 😊")
if __name__ == "__main__":
asyncio.run(send_text())
2. 이미지 전송하기
로컬에 저장된 이미지를 보내려면 bot.send_photo
함수를 사용해야 합니다.
이미지를 바이너리 형식으로 읽기 위해 open
함수에 'rb'
옵션을 사용해야 하죠.
import asyncio
import telegram
TOKEN = "YOUR_TELEGRAM_BOT_TOKEN"
CHAT_ID = "YOUR_CHAT_ID"
async def send_image():
bot = telegram.Bot(TOKEN)
# 'my_image.jpg' 라는 파일이 코드와 같은 경로에 있어야 합니다.
await bot.send_photo(chat_id=CHAT_ID, photo=open('my_image.jpg', 'rb'), caption="코알라가 귀엽네요!")
if __name__ == "__main__":
asyncio.run(send_image())
3. HTML 파일 전송하기
HTML 파일뿐만 아니라 PDF, ZIP 등 모든 종류의 파일을 보낼 때는 bot.send_document
함수를 사용합니다.
이미지와 마찬가지로 파일을 바이너리 형식으로 열어 전송합니다.
import asyncio
import telegram
TOKEN = "YOUR_TELEGRAM_BOT_TOKEN"
CHAT_ID = "YOUR_CHAT_ID"
async def send_html_file():
bot = telegram.Bot(TOKEN)
# 'report.html' 라는 파일이 코드와 같은 경로에 있어야 합니다.
await bot.send_document(chat_id=CHAT_ID, document=open('report.html', 'rb'), filename="오늘의리포트.html")
if __name__ == "__main__":
asyncio.run(send_html_file())
STEP 2: 고급 기능! (주기적 메시지 & 명령어)
이제 봇을 조금 더 봇답게 만들어 볼까요?
사용자의 명령에 반응하고, 정해진 시간에 스스로 메시지를 보내는 기능입니다.
이를 위해서는 Application
객체를 사용해야 해요.
1. 봇 명령어 등록하고 응답하기 🙋♂️
사용자가 /start
나 /help
같은 명령어를 입력했을 때 봇이 특정 행동을 하도록 설정해 보겠습니다.
CommandHandler
를 사용하면 특정 명령어를 감지하여 지정된 함수를 실행할 수 있습니다.
update
: 사용자의 메시지 등 텔레그램으로부터 받은 모든 정보를 담고 있는 객체입니다.context
: 메시지를 보낼 때 사용하는 bot 객체 등을 포함하는 객체입니다.
from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes
# 설정
TOKEN = "YOUR_TELEGRAM_BOT_TOKEN"
# /start 명령어에 대한 답변 함수
async def start_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
user = update.effective_user
await update.message.reply_html(
rf"안녕하세요, {user.mention_html()}님! 텔레그램 봇에 오신 것을 환영합니다.",
)
# /help 명령어에 대한 답변 함수
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
await update.message.reply_text("저는 여러분들을 돕기 위한 봇 입니다!")
def main() -> None:
# Application 객체 생성
application = Application.builder().token(TOKEN).build()
# 명령어 핸들러 등록
application.add_handler(CommandHandler("start", start_command))
application.add_handler(CommandHandler("help", help_command))
# 봇 실행 (사용자가 메시지를 보낼 때까지 대기)
print("봇이 시작되었습니다. 텔레그램에서 명령어를 입력해 보세요.")
application.run_polling()
if __name__ == "__main__":
main()
위 코드를 실행하고 텔레그램 봇 채팅방에서 /help
를 입력하면 봇이 반갑게 인사하는 것을 볼 수 있습니다.
2. 주기적으로 메시지 전송하기 ⏰
2-1. 커맨드(CommandHandler) 연동
매일 아침 9시에 데일리 리포트를 보내거나, 1시간마다 특정 정보를 알려주는 등의 기능을 구현할 수 있습니다.
Application
객체의 job_queue
를 사용하면 매우 간단하게 구현 가능합니다!
run_repeating
함수는 특정 간격으로 지정된 함수를 계속해서 실행해 줍니다.
import datetime
from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes
# 설정
TOKEN = "YOUR_TELEGRAM_BOT_TOKEN"
CHAT_ID = "YOUR_CHAT_ID"
# 주기적으로 실행될 함수
async def send_periodic_message(context: ContextTypes.DEFAULT_TYPE) -> None:
job = context.job
current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
message = f"⏰ 주기적인 알림입니다! 현재 시간: {current_time}"
await context.bot.send_message(job.chat_id, text=message)
# /start 명령어 입력 시 주기적 메시지 전송 시작
async def start_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
chat_id = update.effective_message.chat_id
# 기존에 등록된 job이 있다면 제거
# context.job_queue.stop() # 혹은 특정 job 이름을 찾아 제거
# 10초마다 send_periodic_message 함수 실행
context.job_queue.run_repeating(send_periodic_message, interval=10, first=1, chat_id=chat_id, name=str(chat_id))
await update.message.reply_text("✅ 10초 간격으로 주기적인 메시지 전송을 시작합니다.")
def main() -> None:
application = Application.builder().token(TOKEN).build()
application.add_handler(CommandHandler("start", start_command))
print("봇이 시작되었습니다. /start 를 입력하여 주기적 메시지를 받아보세요.")
application.run_polling()
if __name__ == "__main__":
main()
이제 /start
명령어를 입력하면 봇이 10초에 한 번씩 현재 시간을 알려주는 메시지를 보내기 시작합니다.
2-2. 함수 연동
사용자의 명령어 입력(CommandHandler
) 없이,
프로그램이 시작하자마자 바로 특정 함수를 주기적으로 실행하도록 하려면 다음과 같이 코드를 작성하면 됩니다.
이 방법은 사용자의 상호작용 없이, 서버 모니터링, 데이터 자동 리포팅 등 백그라운드에서 정해진 작업을 수행하는 봇을 만들 때 매우 유용합니다.
핵심은 Application
객체를 만든 직후,
봇을 실행하는 application.run_polling()
을 호출하기 전에 job_queue.run_repeating()
을 먼저 설정해주는 것입니다.
import asyncio
import datetime
from telegram.ext import Application, ContextTypes
# --- 설정 ---
TOKEN = "YOUR_TELEGRAM_BOT_TOKEN" # 텔레그램 봇 토큰
CHAT_ID = "YOUR_CHAT_ID" # 메시지를 받을 채팅 ID
# --- 주기적으로 실행될 비동기 함수 ---
# 이 함수는 봇의 다른 기능과 독립적으로 실행됩니다.
async def report_status(context: ContextTypes.DEFAULT_TYPE) -> None:
"""서버 상태나 데이터 등을 주기적으로 보고하는 함수"""
current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 예시: 간단한 텍스트 메시지 전송
message = f"✅ [자동 리포트] 현재 시각: {current_time}. 모든 시스템이 정상입니다."
# context.bot을 통해 메시지 전송
await context.bot.send_message(chat_id=context.job.chat_id, text=message)
def main() -> None:
"""봇을 설정하고 실행하는 메인 함수"""
# 1. Application 객체 생성
application = Application.builder().token(TOKEN).build()
# 2. JobQueue를 가져와 주기적인 작업 예약
# application.run_polling() 전에 실행하는 것이 중요합니다.
job_queue = application.job_queue
# 30분(1800초) 간격으로 report_status 함수를 실행하도록 예약합니다.
# first=1 옵션은 프로그램 시작 후 1초 뒤에 첫 작업을 바로 실행하라는 의미입니다.
job_queue.run_repeating(report_status, interval=1800, first=1, chat_id=CHAT_ID)
# 3. 봇 실행
# run_polling()이 호출되면, 위에서 예약한 작업(Job)도 함께 시작되고
# 프로그램이 종료될 때까지 계속 실행됩니다.
print("✅ 봇이 시작되었습니다. 30분마다 자동으로 메시지를 전송합니다.")
application.run_polling()
if __name__ == "__main__":
main()
3. OOP 구조에서의 코드 작성법
기존의 함수들을 MyBot
이라는 클래스 안으로 가져와 메서드로 만들고, 봇의 상태(토큰, 채팅 ID 등)는 인스턴스 변수로 관리하려고 합니다!
MyBot 클래스 구조 표로 살펴보기
구조 | 설명 |
---|---|
__init__(self, token, chat_id) |
- 클래스의 인스턴스가 생성될 때 가장 먼저 호출됩니다. - 봇의 토큰과 기본 채팅 ID를 인스턴스 변수(self.token, self.chat_id)로 저장합니다. - Application 객체를 생성하여 self.application에 저장합니다. |
_start_command(self, update, context) (명령어 핸들러 메서드) |
- /start 명령어에 대한 로직을 담고 있는 메서드입니다.- 클래스 내부의 다른 메서드나 변수에 접근해야 할 경우 self를 통해 접근할 수 있습니다. |
_send_periodic_message(self, context) (주기적 실행 메서드) |
- job_queue 가 주기적으로 호출할 메서드입니다. |
run(self) (봇 실행 메서드) |
핸들러 등록, job_queue 설정 등 봇을 실행하기 위한 모든 준비 과정을 담당하고, 마지막에 run_polling()을 호출하여 봇을 시작시킵니다. |
전체 예제 코드
import logging
import datetime
from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes
# 로깅 설정 (디버깅에 유용)
logging.basicConfig(
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO
)
class MyBot:
def __init__(self, token: str, chat_id: str):
"""봇 생성자: 초기 설정 담당"""
self.chat_id = chat_id
self.application = Application.builder().token(token).build()
# 핸들러와 Job을 등록합니다.
self._register_handlers()
self._register_jobs()
def _register_handlers(self):
"""명령어 핸들러를 등록합니다."""
self.application.add_handler(CommandHandler("start", self._start_command))
def _register_jobs(self):
"""주기적인 작업을 JobQueue에 등록합니다."""
self.application.job_queue.run_repeating(
self._send_periodic_message,
interval=15, # 15초 간격
first=1, # 1초 후 첫 실행
chat_id=self.chat_id
)
async def _start_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""/start 명령어 수신 시 호출될 메서드"""
user_name = update.effective_user.first_name
await update.message.reply_html(
f"🤖 안녕하세요, {user_name}님!\n객체지향 구조의 봇이 성공적으로 시작되었습니다."
)
async def _send_periodic_message(self, context: ContextTypes.DEFAULT_TYPE) -> None:
"""주기적으로 메시지를 보내는 메서드"""
current_time = datetime.datetime.now().strftime("%H:%M:%S")
message = f"⏰ [OOP Bot] 주기적인 알림입니다. 현재 시각: {current_time}"
await context.bot.send_message(chat_id=context.job.chat_id, text=message)
def run(self):
"""봇을 실행합니다."""
logging.info("객체지향 봇을 시작합니다...")
self.application.run_polling()
logging.info("봇이 종료되었습니다.")
if __name__ == "__main__":
# --- 설정 ---
TOKEN = "YOUR_TELEGRAM_BOT_TOKEN" # 텔레그램 봇 토큰
CHAT_ID = "YOUR_CHAT_ID" # 메시지를 받을 채팅 ID
# 1. MyBot 클래스의 인스턴스를 생성합니다.
bot_instance = MyBot(token=TOKEN, chat_id=CHAT_ID)
# 2. 봇을 실행합니다.
bot_instance.run()
3-1. 트러블슈팅
코드 실행 시 아래와 같은 에러가 발생하였습니다!
File "/home/dev/git/resource/resource_script.py", line 18, in __init__
self._register_jobs()
File "/home/dev/git/resource/resource_script.py", line 25, in _register_jobs
self.application.job_queue.run_repeating(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'run_repeating'
확인해보니 다음 오류는 python-telegram-bot
라이브러리의 JobQueue
기능에 필요한 추가 패키지가 설치되지 않아서 발생하는 문제였습니다.
v20 버전부터 JobQueue
는 선택적 기능으로 분리되어, 사용하려면 별도로 설치해 주어야 합니다.
오류 메시지에 나온 AttributeError: 'NoneType' object has no attribute 'run_repeating'
은
self.application.job_queue
가 None으로 설정되었음을 의미하며, 이는 관련 패키지가 없기 때문입니다.
해결 방법 🛠️
터미널에서 아래 명령을 실행해 JobQueue
를 포함한 패키지를 설치해주세요.
pip install --upgrade "python-telegram-bot[job-queue]"