Telegram бот на Python, отправка файлов, встроенная клавиатура

Telegram бот на Python, отправка файлов, встроенная клавиатура

Автор: Рамис | Статьи 26 сентября 2021

Часть 1. Простой Telegram бот на Python, метод getUpdates

Часть 2. Telegram бот на Python, отправка файлов, встроенная клавиатура

Часть 3. Telegram бот на Python, работа с геолокацией пользователяа

Это вторая часть статьи, где мы продолжим создавать нашего телеграм бота на Python, и научим его отправлять файлы и выводить настраиваемую клавиатуру.

Отправка файлов Telegram API

В Telegram API есть три способа отправки файлов, для демонстрации воспользуемся методом sendPhoto и добавим три функции для отправки фотографии.

Первая способ: Предоставить файл по URL, Telegram скачает и отправит его (максимальный размер 5 МБ).

def send_photo_url(chat_id, img_url):
    requests.get(f'{URL}{TOKEN}/sendPhoto?chat_id={chat_id}&photo={img_url}')

Второй способ: Отправить файл с компьютера (максимальный размер фотографий - 10 МБ, для остальных файлов - 50 МБ).

def send_photo_file(chat_id, img):
    files = {'photo': open(img, 'rb')}
    requests.post(f'{URL}{TOKEN}/sendPhoto?chat_id={chat_id}', files=files)

Третий способ: Отправить, передав в параметрах file_id файла который уже хранится где-то на серверах Telegram (ограничений нет).

def send_photo_file_id(chat_id, file_id):
    requests.get(f'{URL}{TOKEN}/sendPhoto?chat_id={chat_id}&photo={file_id}')

Проверка

Почти все готово, осталось немного отредактировать функцию check_message и приступим к проверке бота.

def check_message(chat_id, message):
    if message.lower() in ['привет', 'hello']:
        send_message(chat_id, 'Привет :)')
    elif message.lower() in 'фото по url':
        # Отправить URL-адрес картинки (телеграм скачает его и отправит)
        send_photo_url(chat_id, 'https://ramziv.com/static/assets/img/home-bg.jpg')
    elif message.lower() in 'фото с компьютера':
        # Отправить файл с компьютера
        send_photo_file(chat_id, 'photo.jpg')
    elif message.lower() in 'фото с сервера телеграм':
        # Отправить id файла (файл уже хранится где-то на серверах Telegram) 
        send_photo_file_id(chat_id, 'AgACAgIAAxkBAAMqYVGBbdbivL53IzKLfUKUClBnB0cAApy0MRtfMZBKHL0tNw9aITwBAAMCAAN4AAMhBA')

Полный код

import requests
import time

TOKEN = 'токен'
URL = 'https://api.telegram.org/bot'

def get_updates(offset=0):
    result = requests.get(f'{URL}{TOKEN}/getUpdates?offset={offset}').json()
    return result['result']

def send_message(chat_id, text):
    requests.get(f'{URL}{TOKEN}/sendMessage?chat_id={chat_id}&text={text}')

def send_photo_url(chat_id, img_url):
    requests.get(f'{URL}{TOKEN}/sendPhoto?chat_id={chat_id}&photo={img_url}')

def send_photo_file(chat_id, img):
    files = {'photo': open(img, 'rb')}
    requests.post(f'{URL}{TOKEN}/sendPhoto?chat_id={chat_id}', files=files)

def send_photo_file_id(chat_id, file_id):
    requests.get(f'{URL}{TOKEN}/sendPhoto?chat_id={chat_id}&photo={file_id}')

def check_message(chat_id, message):
    if message.lower() in ['привет', 'hello']:
        send_message(chat_id, 'Привет :)')
    elif message.lower() in 'фото по url':
        # Отправить URL-адрес картинки (телеграм скачает его и отправит)
        send_photo_url(chat_id, 'https://ramziv.com/static/assets/img/home-bg.jpg')
    elif message.lower() in 'фото с компьютера':
        # Отправить файл с компьютера
        send_photo_file(chat_id, 'photo.jpg')
    elif message.lower() in 'фото с сервера телеграм':
        # Отправить id файла (файл уже хранится где-то на серверах Telegram) 
        send_photo_file_id(chat_id, 'AgACAgIAAxkBAAMqYVGBbdbivL53IzKLfUKUClBnB0cAApy0MRtfMZBKHL0tNw9aITwBAAMCAAN4AAMhBA')


def run():
    update_id = get_updates()[-1]['update_id'] # Присваиваем ID последнего отправленного сообщения боту
    while True:
        time.sleep(2)
        messages = get_updates(update_id) # Получаем обновления
        for message in messages:
            # Если в обновлении есть ID больше чем ID последнего сообщения, значит пришло новое сообщение
            if update_id < message['update_id']:
                update_id = message['update_id'] # Присваиваем ID последнего отправленного сообщения боту
                # Отвечаем тому кто прислал сообщение боту
                check_message(message['message']['chat']['id'], message['message']['text'])

if __name__ == '__main__':
    run()

Результат проверки:

Фото по url

телеграм бота на Python

Фото с компьютера

телеграм бота на Python

Фото с сервера телеграм

телеграм бота на Python

Таким образом вы можете отправить документ, видео, или аудиофайл заменив в URL метод sendPhoto на подходящий.

  • sendVoice Используйте этот метод для отправки аудиофайлов, если вы хотите, чтобы клиент Telegram отображал файл как воспроизводимое голосовое сообщение.
  • sendDocument Используйте этот метод для отправки общих файлов.
  • sendAudio Используйте этот метод для отправки аудиофайлов, если вы хотите, чтобы клиент Telegram отображал их в музыкальном проигрывателе.
  • sendVideo Используйте этот метод для отправки видеофайлов, клиент Telegram поддерживают видео в формате mp4 (другие форматы могут быть отправлены как документ ).
  • sendPhoto Используйте этот метод для отправки фотографий.

С полным списком методов можно ознакомиться здесь

Встроенная клавиатура

Добавим две функции для вывода настраиваемой клавиатуры в телеграм

InlineKeyboardMarkup - Этот объект представляет собой встроенную клавиатуру, которая появляется рядом с отправленным сообщением.

def inline_keyboard(chat_id, text):
    reply_markup = {'inline_keyboard': [[{'text': 'Наш сайт', 'url': 'https://ramziv.com'}]]}
    data = {'chat_id': chat_id, 'text': text, 'reply_markup': json.dumps(reply_markup)}
    requests.post(f'{URL}{TOKEN}/sendMessage', data=data)

ReplyKeyboardMarkup - Этот объект представляет собой настраиваемую клавиатуру с параметрами ответа

def reply_keyboard(chat_id, text):
    reply_markup ={ "keyboard": [["Фото по url", "Сайт"], ["Привет"]], "resize_keyboard": True, "one_time_keyboard": True}
    data = {'chat_id': chat_id, 'text': text, 'reply_markup': json.dumps(reply_markup)}
    requests.post(f'{URL}{TOKEN}/sendMessage', data=data)

Отредактируем функцию check_message для вывода нашей клавиатуры

def check_message(chat_id, message):
    if message.lower() in ['привет', 'hello']:
        send_message(chat_id, 'Привет :)')
    elif message.lower() in 'сайт':
        inline_keyboard(chat_id, 'Вы можете ознакомиться\nс товаром на сайте')
    elif message.lower() in 'фото по url':
        # Отправить URL-адрес картинки (телеграм скачает его и отправит)
        send_photo_url(chat_id, 'https://ramziv.com/static/assets/img/home-bg.jpg')
    elif message.lower() in 'фото с компьютера':
        # Отправить файл с компьютера
        send_photo_file(chat_id, 'photo.jpg')
    elif message.lower() in 'фото с сервера телеграм':
        # Отправить id файла (файл уже хранится где-то на серверах Telegram) 
        send_photo_file_id(chat_id, 'AgACAgIAAxkBAAMqYVGBbdbivL53IzKLfUKUClBnB0cAApy0MRtfMZBKHL0tNw9aITwBAAMCAAN4AAMhBA')
    else:
        reply_keyboard(chat_id, 'Вот что я умею')

Проверка

Проверим как все работает

Отправим боту сообщение Сайт

телеграм бота на Python

Если отправить сообщение на которые бот не может дать ответ, он выведет клавиатуру и сообщение Вот что я умею

телеграм бота на Python

Полный код

import requests
import time
import json

TOKEN = 'токен'
URL = 'https://api.telegram.org/bot'

def get_updates(offset=0):
    result = requests.get(f'{URL}{TOKEN}/getUpdates?offset={offset}').json()
    return result['result']

def send_message(chat_id, text):
    requests.get(f'{URL}{TOKEN}/sendMessage?chat_id={chat_id}&text={text}')

def send_photo_url(chat_id, img_url):
    requests.get(f'{URL}{TOKEN}/sendPhoto?chat_id={chat_id}&photo={img_url}')

def send_photo_file(chat_id, img):
    files = {'photo': open(img, 'rb')}
    requests.post(f'{URL}{TOKEN}/sendPhoto?chat_id={chat_id}', files=files)

def send_photo_file_id(chat_id, file_id):
    requests.get(f'{URL}{TOKEN}/sendPhoto?chat_id={chat_id}&photo={file_id}')

def inline_keyboard(chat_id, text):
    reply_markup = {'inline_keyboard': [[{'text': 'Наш сайт', 'url': 'https://ramziv.com'}]]}
    data = {'chat_id': chat_id, 'text': text, 'reply_markup': json.dumps(reply_markup)}
    requests.post(f'{URL}{TOKEN}/sendMessage', data=data)

def reply_keyboard(chat_id, text):
    reply_markup ={ "keyboard": [["Фото по url", "Сайт"], ["Привет"]], "resize_keyboard": True, "one_time_keyboard": True}
    data = {'chat_id': chat_id, 'text': text, 'reply_markup': json.dumps(reply_markup)}
    requests.post(f'{URL}{TOKEN}/sendMessage', data=data)

def check_message(chat_id, message):
    if message.lower() in ['привет', 'hello']:
        send_message(chat_id, 'Привет :)')
    elif message.lower() in 'сайт':
        inline_keyboard(chat_id, 'Вы можете ознакомиться\nс товаром на сайте')
    elif message.lower() in 'фото по url':
        # Отправить URL-адрес картинки (телеграм скачает его и отправит)
        send_photo_url(chat_id, 'https://ramziv.com/static/assets/img/home-bg.jpg')
    elif message.lower() in 'фото с компьютера':
        # Отправить файл с компьютера
        send_photo_file(chat_id, 'photo.jpg')
    elif message.lower() in 'фото с сервера телеграм':
        # Отправить id файла (файл уже хранится где-то на серверах Telegram) 
        send_photo_file_id(chat_id, 'AgACAgIAAxkBAAMqYVGBbdbivL53IzKLfUKUClBnB0cAApy0MRtfMZBKHL0tNw9aITwBAAMCAAN4AAMhBA')
    else:
        reply_keyboard(chat_id, 'Вот что я умею')

def run():
    update_id = get_updates()[-1]['update_id'] # Присваиваем ID последнего отправленного сообщения боту
    while True:
        time.sleep(2)
        messages = get_updates(update_id) # Получаем обновления
        for message in messages:
            # Если в обновлении есть ID больше чем ID последнего сообщения, значит пришло новое сообщение
            if update_id < message['update_id']:
                update_id = message['update_id'] # Присваиваем ID последнего отправленного сообщения боту
                # Отвечаем тому кто прислал сообщение боту
                check_message(message['message']['chat']['id'], message['message']['text'])

if __name__ == '__main__':
    run()
Вот и все, теперь бот может не только поприветствовать, но и отправить файл, и вывести настраиваемую клавиатуру. Скоро я выпушу третью часть, где мы добавим оплату через QIWI кошелек, или любой другой функционал который вы пожелаете. (напишите мне если вы хотите третью часть побыстрее)

Дополнительную информацию о методах вы можете получить в документации.

Комментарии

Рамис
@ramas
06 декабря 2021

Первый комментарий)

Ответить
parampampam888
@parampampam888
31 марта 2022

А как заставить его не падать если он получает не текст а например фотографию или стикер . Ошибка : KeyError: 'text' Я понимаю что нужен фильтр но как его воткнуть что то не пойму.

Ответить
Рамис
@ramas
31 марта 2022

@parampampam888, если вы используете Python 3.8 и выше.

def run():
    update_id = get_updates()[-1]['update_id'] # Сохраняем ID последнего отправленного сообщения боту
    while True:
        time.sleep(2)
        messages = get_updates(update_id) # Получаем обновления
        for message in messages:
            # Если в обновлении есть ID больше чем ID последнего сообщения, значит пришло новое сообщение
            if update_id < message['update_id']:
                update_id = message['update_id']# Сохраняем ID последнего отправленного сообщения боту
                if (user_message := message['message'].get('text')): # Проверим, есть ли текст в сообщении
                    check_message(message['message']['chat']['id'], user_message) # Отвечаем

Ответить
parampampam888
@parampampam888
01 апреля 2022

@ramas, Спасибо , за статью и за помощь !

Ответить
Рамис
@ramas
01 апреля 2022

@parampampam888, Не за что, обращайтесь.

Ответить
yura_mars
@yura_mars
07 сентября 2022

Очень долго искал решение! Спасибо огромное)))

Ответить
Рамис
@ramas
08 сентября 2022

@yura_mars, Всегда пожалуйста)

Ответить
Mango
@Mango
27 июля 2023

Пытаюсь отправить файл как и аудио так и видео ошибка однотипна.

files = {'Godford - Xtz - original mix.mp3': open(img, 'rb')} A=requests.post(f'{URL}{TOKEN}/sendAudio?chat_id={chat_id}', files=files) print(A.text)

{"ok":false,"error_code":400,"description":"Bad Request: there is no audio in the request"}

Ломаю голову второй день, что не так?

Ответить
Рамис
@ramas
27 июля 2023

@Mango, Аудио

files = {'audio': open('Hello.mp3', 'rb')}
requests.post(f'{URL}{TOKEN}/sendAudio?chat_id={chat_id}', files=files)

Документ

files = {'document': open('File.xls', 'rb')}
requests.post(f'{URL}{TOKEN}/sendDocument?chat_id={chat_id}', files=files)

Ответить
Boban123
@Boban123
04 октября 2023

Здравствуйте. Можете подсказать? Я вообще ни разу не программист)) Суть проблемы: на компьютере есть папка куда по фтп прилетают фотографии. Мне нужно чтобы при появлении в папке новой фотографии она сразу же отправлялась в Telegram чат. Как это реализовать?

Ответить
Alex_Gr
@Alex_Gr
20 октября 2023

Присоединяюсь к предыдущей просьбе. За этим и пришел на этот сайт. За остальные материалы большое спасибо, много полезного.

Ответить
Рамис
@ramas
24 октября 2023

@Alex_Gr, @Boban123, Вам нужно получить список всех изображений в папке, отправить каждый в телеграм чат и переместить в другую директорию.

import os 

ftp_folder = r"path\ftp"
old_folder = r"path\old"

while True:
    for file in os. listdir(ftp_folder):
        send_photo_file(chat_id, f"{ftp_folder}\{file}")
        print(f"{ftp_folder}\{file}")
        try:
            os.replace(f"{ftp_folder}\{file}", f"{old_folder}\{file}")
        except PermissionError as e:
            pass

Ответить
Alex_Gr
@Alex_Gr
25 октября 2023

Рамис, спасибо большое! Это то что нужно. Из особенностей - chat_id здесь нужно указывать явно, что логично. Но не сразу понял. os.replace в Винде выдаёт '[Errno 13] Permission denied'. Единственный заработавший вариант - разместить папку old в корне диска d: Ну, пусть там и остаётся.

Ответить
Рамис
@ramas
27 октября 2023

@Alex_Gr, Пожалуйста. Сообщение говорит, что у Вас недостаточно прав. Запуск от имени администратора исправит это.

Ответить
Markdown
Войти