Telegram机器人批量删帖失败:仅删单用户帖子报错求助
Telegram机器人批量删帖报错:MessageToDeleteNotFound 排查与修复
我开发了两个Telegram机器人功能:
- 给点击过
/start按钮的所有用户群发消息的功能 - 按ID批量删除用户消息的功能,但执行时仅成功删除一个用户的消息后就抛出错误:
aiogram.utils.exceptions.MessageToDeleteNotFound: Message to delete not found
功能代码
1. 群发消息功能代码
@dp.message_handler(commands=['Yes'], state=Post.send_post) async def process_name(message: Message, state: FSMContext): for admin in admins: if message.from_user.id == admin: async with state.proxy() as data: data['send_post'] = message.text conn = sqlite3.connect('data.db') cur = conn.cursor() cur.execute(f'SELECT * FROM users') result = cur.fetchall() await state.finish() print(result) try: for z in range(len(result)): print(result[z][0]) await dp.bot.send_photo(chat_id=result[z][0], photo=data['photo'], caption=data['CAPTHION'], reply_markup=kb) print(z) test = message.message_id + 1 await dp.bot.send_message(chat_id=result[z][0], text=f'id поста {test}') except BotBlocked: print('Пользователь заблокировал бота') except ChatNotFound: print('Пользователь не запускал бота')
2. 批量删帖功能代码
@dp.message_handler(commands=['deleted'], state=None) async def send_id(message: Message): for admin in admins: if message.from_user.id == admin: await Post.Sen_id.set() await dp.bot.send_message(chat_id=admin, text='Введите ID поста, который нужно удалить.') await Post.next() @dp.message_handler(state=Post.del_mess) async def deleted_post(message: Message, state: FSMContext): for admin in admins: if message.from_user.id == admin: async with state.proxy() as data: data['sen_id'] = message.text try: conn = sqlite3.connect('data.db') cur = conn.cursor() cur.execute(f'SELECT * FROM users') result = cur.fetchall() #message_ids = int(data['sen_id']) for z in range(len(result)): print('/////////////deleted/////////////') print(result) print(z) await dp.bot.delete_message(chat_id=result[z][0], message_id=data['sen_id']) print('Сообщение удалено') #chat_id = message.chat.id #await dp.bot.delete_message(message.chat.id, message_ids) await dp.bot.send_message(chat_id=admin, text='пост удален') except BotBlocked: print('Пользователь заблокировал бота') except ChatNotFound: print('Пользователь не запускал бота')
错误原因
消息ID全局统一的误解
Telegram中每个用户与机器人的对话是独立的,消息ID是对话内唯一,而非全局统一。你群发时用test = message.message_id + 1(管理员对话的消息ID)作为帖子ID发给用户,但这个ID和用户对话里的消息ID完全不对应,只有碰巧用户对话里有相同数字的消息时才会删除成功,其他情况必然报错。消息ID类型错误
你从状态中获取的data['sen_id']是字符串类型,但delete_message要求message_id是整数,类型不匹配会导致API无法正确识别消息。异常捕获不完整且范围错误
你没有捕获MessageToDeleteNotFound异常,且try-except包裹了整个循环,一旦某个用户触发异常,整个循环直接终止,无法处理后续用户。
修复方案
1. 修改群发逻辑,存储用户对应的真实消息ID
群发时,记录每个用户收到的消息ID到数据库,关联到统一的帖子ID:
@dp.message_handler(commands=['Yes'], state=Post.send_post) async def process_name(message: Message, state: FSMContext): for admin in admins: if message.from_user.id == admin: async with state.proxy() as data: data['send_post'] = message.text conn = sqlite3.connect('data.db') cur = conn.cursor() # 创建帖子消息映射表(如果不存在) cur.execute('CREATE TABLE IF NOT EXISTS post_messages(post_id INTEGER, user_id INTEGER, message_id INTEGER)') conn.commit() cur.execute(f'SELECT * FROM users') result = cur.fetchall() await state.finish() print(result) try: # 用管理员消息ID+1作为全局帖子标识 post_id = message.message_id + 1 for user in result: user_id = user[0] print(user_id) # 发送图片并获取消息对象(包含用户对话中的真实消息ID) photo_msg = await dp.bot.send_photo(chat_id=user_id, photo=data['photo'], caption=data['CAPTHION'], reply_markup=kb) # 发送帖子ID通知并获取消息对象 id_msg = await dp.bot.send_message(chat_id=user_id, text=f'id поста {post_id}') # 存储映射关系到数据库 cur.execute('INSERT INTO post_messages VALUES (?, ?, ?)', (post_id, user_id, photo_msg.message_id)) cur.execute('INSERT INTO post_messages VALUES (?, ?, ?)', (post_id, user_id, id_msg.message_id)) conn.commit() print(f"已记录用户{user_id}的消息ID:{photo_msg.message_id}, {id_msg.message_id}") except BotBlocked: print(f'Пользователь {user_id} заблокировал бота') except ChatNotFound: print(f'Пользователь {user_id} не запускал бота') finally: conn.close()
2. 修改删帖逻辑,从数据库获取对应消息ID
@dp.message_handler(commands=['deleted'], state=None) async def send_id(message: Message): for admin in admins: if message.from_user.id == admin: await Post.Sen_id.set() await dp.bot.send_message(chat_id=admin, text='Введите ID поста, который нужно удалить.') await Post.next() @dp.message_handler(state=Post.del_mess) async def deleted_post(message: Message, state: FSMContext): for admin in admins: if message.from_user.id == admin: try: # 转换输入为整数类型 post_id = int(message.text) async with state.proxy() as data: data['sen_id'] = post_id conn = sqlite3.connect('data.db') cur = conn.cursor() # 根据帖子ID查询所有需要删除的消息 cur.execute('SELECT user_id, message_id FROM post_messages WHERE post_id = ?', (post_id,)) messages_to_delete = cur.fetchall() # 逐个处理用户的消息删除 for user_id, msg_id in messages_to_delete: try: await dp.bot.delete_message(chat_id=user_id, message_id=msg_id) print(f"Удалено сообщение {msg_id} для пользователя {user_id}") except BotBlocked: print(f'Пользователь {user_id} заблокировал бота') except ChatNotFound: print(f'Пользователь {user_id} не запускал бота') except MessageToDeleteNotFound: print(f'Сообщение {msg_id} для пользователя {user_id} не найдено') await dp.bot.send_message(chat_id=admin, text='пост удален') await state.finish() except ValueError: await dp.bot.send_message(chat_id=admin, text='Некорректный ID поста,请输入数字') finally: if 'conn' in locals(): conn.close()
3. 额外优化点
- 数据库连接放到
finally块确保关闭,避免连接泄漏 - 对单个用户的删除操作单独捕获异常,不影响其他用户
- 验证输入的帖子ID是否为有效整数,提前拦截错误输入
内容的提问来源于stack exchange,提问作者user380703
相关产品推荐
相关产品推荐

