Profile picture

[Python] 파이썬으로 텔레그램(telegram) 봇 만들기 - 텍스트, 이미지, 파일 전송부터 주기적 알림, 명령어 처리까지

JaehyoJJAng2025년 01월 10일

개요

오늘은 파이썬 언어로 텔레그램 봇을 만들고, 다양한 메시지를 보내는 방법에 대해 총정리해 보겠습니다.


텍스트는 물론 이미지, 파일 전송과 특정 시간에 맞춰 주기적으로 메시지를 보내는 방법, 그리고 사용자가 명령어를 입력했을 때 봇이 반응하게 하는 방법까지!


STEP 0: 시작하기 전에!

봇 생성

가장 먼저 텔레그램 봇을 만들고, 파이썬으로 제어하기 위한 API 토큰을 발급받아야 합니다.

1. 텔레그램 앱에서 /newbot 이라고 채팅을 입력하면 봇 채팅방을 개설할 수 있는 단계가 시작됩니다.
image


2. 봇 채팅방 이름을 지정해줄게요.
image


3. 봇의 이름을 지정해줍시다!. 중요한 점은 봇의 이름을 지정할 때는 봇 이름 마지막에 _bot 이라고 끝나야 합니다.
image


4. 이후 봇 채팅방이 개설되고, 다음의 봇 토큰이 생성되었습니다. 해당 토큰은 이번 실습에서만 사용하고 이후 삭제하겠습니다.
image


5. 마지막으로 생성된 봇 채팅방 검색 후, start 버튼을 클릭하면 됩니다. (본인이 생성한 봇을 정확히 찾도록 합시다.)
image


라이브러리 설치

이제 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를 입력하면 봇이 반갑게 인사하는 것을 볼 수 있습니다.

image


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]"

Loading script...