Передача файлов в Telegram-ботах с aiogram: полный обзор
Отправка файлов через Telegram-бота на aiogram
Telegram-боты часто требуют отправки пользователям различных файлов: изображений, документов, аудио, видео. В aiogram (асинхронная библиотека для Python) это реализуется через методы класса Bot, такие как send_document, send_photo, send_video, send_audio и другие. Рассмотрим наиболее эффективный подход и альтернативные варианты, включая типичные проблемы.
Основное решение: отправка файла по file_id или URL
Самый быстрый способ – использовать уже загруженный на сервер Telegram file_id (строка) или внешний URL. Этот подход не требует повторной загрузки файла на сервер Telegram, если он уже известен.
from aiogram import Bot, Dispatcher, types
from aiogram.utils import executor
API_TOKEN = 'ВАШ_ТОКЕН'
bot = Bot(token=API_TOKEN)
dp = Dispatcher(bot)
@dp.message_handler(commands=['send_file'])
async def send_file_example(message: types.Message):
# Отправка документа по file_id (получен ранее)
file_id = 'BQACAgIAAxkBAA...'
await bot.send_document(message.chat.id, file_id)
@dp.message_handler(commands=['send_photo'])
async def send_photo_example(message: types.Message):
# Отправка фото по URL
photo_url = 'https://example.com/image.jpg'
await bot.send_photo(message.chat.id, photo_url)
if __name__ == '__main__':
executor.start_polling(dp, skip_updates=True)Aiogram python file (отправка файлов через telegram-бота на aiogram в python)
Как отправить файл, который уже есть на сервере Telegram или по ссылке?
Возможные ошибки:
- Неверный file_id – бот не может найти файл. Решение: убедиться, что file_id получен от того же бота и не устарел (file_id постоянны для одного бота).
- Некорректный URL – сервер Telegram не может загрузить изображение. Решение: проверьте доступность URL и правильность MIME-типа.
Вариант 1: отправка локального файла (с компьютера)
Когда файл хранится на локальной файловой системе или генерируется на лету. Используется класс InputFile из aiogram.
from aiogram.types import InputFile
@dp.message_handler(commands=['local_doc'])
async def send_local_document(message: types.Message):
doc = InputFile(path_or_bytesio='/home/user/my_document.pdf')
await bot.send_document(message.chat.id, doc, caption='Локальный документ')
Как загрузить файл из папки на сервере бота?
Ошибка: файл не найден или нет прав. Решение: проверьте путь, права на чтение. Для Windows используйте двойные обратные слеши или raw-строки.
Вариант 2: отправка файла из памяти (BytesIO)
Если файл генерируется в оперативной памяти (например, результат работы библиотеки Pillow).
from io import BytesIO
from PIL import Image
@dp.message_handler(commands=['generate_image'])
async def send_generated_image(message: types.Message):
img = Image.new('RGB', (100, 100), color='red')
bio = BytesIO()
img.save(bio, format='PNG')
bio.seek(0)
await bot.send_photo(message.chat.id, InputFile(bio, filename='red_square.png'))
Как отправить изображение, созданное в Python (например, график), не сохраняя на диск?
Некорректное имя файла без расширения – Telegram может не распознать тип. Решение: всегда передавайте filename с правильным расширением.
Вариант 3: отправка нескольких файлов одновременно
Используйте методы send_media_group для отправки группы медиафайлов (до 10).
from aiogram.types import MediaGroup, InputMediaPhoto, InputMediaDocument
@dp.message_handler(commands=['albums'])
async def send_album(message: types.Message):
album = MediaGroup()
album.attach(InputMediaPhoto(open('photo1.jpg', 'rb'), caption='Фото 1'))
album.attach(InputMediaPhoto(open('photo2.jpg', 'rb')))
album.attach(InputMediaDocument(open('doc.pdf', 'rb'), filename='doc.pdf'))
await message.reply_media_group(media=album)
# или await bot.send_media_group(message.chat.id, album)
Как отправить несколько фото и документов одним сообщением?
Превышение лимита (более 10) – Telegram не поддерживает. Решение: разбить на несколько групп. Для смешанных типов (фото+документ) группа будет отображаться некорректно? На самом деле разрешены только однотипные медиа в группе (все фото или все документы).
Вариант 4: отправка файла с клавиатурой или кнопками
Файл можно отправить вместе с inline-клавиатурой.
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
@dp.message_handler(commands['file_with_btn'])
async def send_file_with_keyboard(message: types.Message):
keyboard = InlineKeyboardMarkup()
keyboard.add(InlineKeyboardButton('Скачать', url='https://example.com'))
await bot.send_document(message.chat.id, 'file_id_123', reply_markup=keyboard)
Как добавить кнопку под файлом?
Расширенные примеры и нестандартные сценарии
Пример 1: Отправка файла с переопределением имени и MIME-типа
Иногда нужно явно указать имя файла, которое увидит пользователь. Для этого используется InputFile с параметром filename. MIME-тип можно задать через headers, но обычно Telegram определяет его автоматически.
from aiogram.types import InputFile
import aiohttp
@dp.message_handler(commands=['rename_file'])
async def send_renamed_file(message: types.Message):
# Скачиваем файл из интернета через aiohttp
async with aiohttp.ClientSession() as session:
async with session.get('https://example.com/files/data.csv') as resp:
content = await resp.read()
# Оборачиваем в BytesIO и задаём имя
bio = BytesIO(content)
input_file = InputFile(bio, filename='отчет_2025.csv')
await bot.send_document(message.chat.id, input_file)
# Результат: пользователь увидит сообщение с файлом "отчет_2025.csv"
Пример 2: Отправка файла большого размера (до 50 МБ через бота)
Telegram ограничивает размер загружаемого файла через ботов до 50 МБ. Если файл больше, потребуется использовать серверный метод загрузки через sendDocument с разбивкой на части? На самом деле, aiogram поддерживает файлы до 50 МБ напрямую. Ошибки возникают, если файл превышает лимит.
@dp.message_handler(commands=['large_file'])
async def send_large_file(message: types.Message):
try:
# Допустим, файл размером 45 МБ
with open('large_video.mp4', 'rb') as f:
await bot.send_video(message.chat.id, InputFile(f))
except Exception as e:
await message.reply(f'Ошибка: {e}')
# Если файл превышает 50 МБ, будет ошибка: Request Entity Too Large. Решение – разделить файл на части или использовать Telegram API для прямой загрузки через сервер.
Пример 3: Отправка файла с кастомной подписью и parse_mode
Подпись (caption) поддерживает HTML и Markdown. Можно форматировать текст.
@dp.message_handler(commands=['caption_html'])
async def send_with_html_caption(message: types.Message):
caption = 'Жирный текст\nКурсив\nСсылка'
await bot.send_photo(message.chat.id, 'file_id_abc', caption=caption, parse_mode='HTML')
Пользователь увидит фото с форматированным текстом под ним.
Пример 4: Отправка файла с принудительной загрузкой (force document)
Если нужно отправить изображение как документ, а не как фото (чтобы не было превью в галерее), используйте send_document даже для изображений.
@dp.message_handler(commands=['force_doc'])
async def send_image_as_document(message: types.Message):
# изображение отправится как файл .png
await bot.send_document(message.chat.id, InputFile('image.png'))
# Эквивалент без InputFile: await bot.send_document(message.chat.id, open('image.png', 'rb'))
В чате появится иконка документа, а не картинка.
Пример 5: Отправка файла с указанием thumb (миниатюры)
Для видео или документов можно задать миниатюру, которая будет отображаться в превью.
@dp.message_handler(commands=['with_thumb'])
async def send_video_with_thumb(message: types.Message):
video_file = InputFile('video.mp4')
thumb_file = InputFile('thumb.jpg') # миниатюра PNG/JPG, не более 320x320
await bot.send_video(message.chat.id, video_file, thumb=thumb_file)
Видео в сообщении будет иметь превью в виде вашей картинки.
Пример 6: Отправка файла из URL с асинхронной загрузкой
Рекомендуется не блокировать событийный цикл при загрузке по сети. Используйте aiohttp.
import aiohttp
from aiogram.types import InputFile
from io import BytesIO
@dp.message_handler(commands=['download_and_send'])
async def download_and_send(message: types.Message):
url = 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf'
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
data = await resp.read()
bio = BytesIO(data)
await bot.send_document(message.chat.id, InputFile(bio, filename='dummy.pdf'))
Бот скачает PDF и отправит его пользователю.
Пример 7: Использование file_id повторно для отправки
После того как файл загружен, Telegram возвращает file_id. Его можно сохранить в базе данных и использовать повторно без повторной загрузки.
@dp.message_handler(content_types=['document'])
async def get_file_id(message: types.Message):
file_id = message.document.file_id
# сохраняем file_id
await message.reply(f'file_id сохранён: {file_id}')
@dp.message_handler(commands=['resend'])
async def resend_saved_file(message: types.Message):
saved_file_id = 'полученный_ранее_file_id'
await bot.send_document(message.chat.id, saved_file_id)
После повторного вызова команды /resend бот отправит тот же документ почти мгновенно.