Telegram Bot图片存储路径异常问题排查求助
Telegram Bot 图片存储异常问题解决
问题现象
用户点击send_mem按钮后,后续无论点击send_mem还是send_motivator按钮,发送的图片都会保存到/mem文件夹,无法按选择的按钮保存到对应目录。
问题根源
原代码中,picture_saver函数每次被调用时都会重复注册同一个@dp.message_handler(content_types=ContentType.PHOTO)处理器。Aiogram的Dispatcher会按处理器注册顺序匹配请求,第一次调用picture_saver("photo/mem")后,这个处理器就被固定绑定到了"photo/mem"路径,后续再调用picture_saver("photo/motivator")注册的新处理器不会生效(因为第一个处理器已经先匹配到图片消息)。
这种动态注册处理器的方式完全错误,正确的做法是用**状态机(FSM)**记录用户当前选择的保存路径,再根据状态处理后续的图片上传。
修复方案
使用Aiogram的FSM(有限状态机)跟踪用户操作状态,完整修复代码如下:
import logging import os import random from aiogram import Bot, Dispatcher, types from aiogram.contrib.fsm_storage.memory import MemoryStorage from aiogram.types import ReplyKeyboardMarkup, KeyboardButton, ContentType from aiogram.utils import executor from aiogram.dispatcher import FSMContext from aiogram.dispatcher.filters.state import State, StatesGroup # 设置日志级别 logging.basicConfig(level=logging.INFO) # 初始化bot和dispatcher bot = Bot(token='xxxxxx') dp = Dispatcher(bot, storage=MemoryStorage()) # 定义状态类,保存用户当前选择的保存路径 class SavePhotoState(StatesGroup): waiting_for_photo = State() save_path = State() # 随机获取图片函数 def random_image(path): folder = path files = os.listdir(folder) paths = [os.path.join(folder, file) for file in files] random_path = random.choice(paths) image = open(random_path, 'rb') return image # /start命令处理器 @dp.message_handler(commands=['start']) async def start_command(message: types.Message): show_mem = KeyboardButton('show_mem') show_motivator = KeyboardButton('show_motivator') show_art = KeyboardButton('show_art') send_mem = KeyboardButton('send_mem') send_motivator = KeyboardButton('send_motivator') keyboard = ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True).add( show_mem, show_motivator, show_art, send_mem, send_motivator ) await bot.send_message(message.from_user.id, 'Hey!', reply_markup=keyboard) # 文本按钮处理器 @dp.message_handler(content_types=['text']) async def button_processing(message: types.Message, state: FSMContext): if message.text == 'show_mem': await bot.send_photo(message.from_user.id, photo=random_image("photo/mem")) elif message.text == 'show_motivator': await bot.send_photo(message.from_user.id, photo=random_image("photo/motivator")) elif message.text == 'show_art': await bot.send_photo(message.from_user.id, photo=random_image("photo/photo")) elif message.text == 'send_mem': # 设置状态和保存路径 await state.update_data(save_path="photo/mem") await SavePhotoState.waiting_for_photo.set() await message.answer("请发送要保存的图片") elif message.text == 'send_motivator': await state.update_data(save_path="photo/motivator") await SavePhotoState.waiting_for_photo.set() await message.answer("请发送要保存的图片") # 图片处理器,仅在等待图片状态时触发 @dp.message_handler(content_types=ContentType.PHOTO, state=SavePhotoState.waiting_for_photo) async def save_photo(message: types.Message, state: FSMContext): # 获取之前保存的路径 data = await state.get_data() save_path = data.get("save_path") photo = message.photo[-1] file = await photo.get_file() # 修复原代码中message.text为None的问题,改用message_id作为文件名 filename = os.path.join(save_path, f"{message.message_id}.jpg") await bot.download_file(file.file_path, filename) await message.answer("Фото сохранено!") # 结束状态,重置为初始状态 await state.finish() if __name__ == '__main__': executor.start_polling(dp, skip_updates=True)
关键改进点
- 用
StatesGroup定义状态,跟踪用户是否处于等待上传图片的状态 - 点击
send_mem/send_motivator时,通过state.update_data保存目标路径,并切换到等待图片的状态 - 图片处理器通过
state=SavePhotoState.waiting_for_photo过滤,只处理处于该状态的用户发送的图片 - 修复了原代码中
message.text在图片消息中为None的错误(原代码会生成无效文件名) - 处理完图片后调用
await state.finish()重置状态,避免影响后续操作
内容的提问来源于stack exchange,提问作者DEAD END TV
相关产品推荐
相关产品推荐

