You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Telegram Bot嵌入带链接按钮遇KeyError:问题排查与求助

Telegram Bot添加带链接按钮功能的KeyError问题解决

问题描述

我正在Telegram Bot中开发一个可为任意文本消息添加带链接按钮的功能,核心代码如下:

message_user_send = {}
name_of_url = {}
url_user_send = {}

############################ 
@bot.message_handler(commands=['aaa'])
def send(message):
    msg1 = bot.send_message(message.chat.id, 'Put main text')
    bot.register_next_step_handler(msg1, name_of_link)

def name_of_link(message):
    message_user_send[message.text] = message.text
    msg1 = bot.send_message(message.chat.id, 'Put name of url')
    bot.register_next_step_handler(msg1, send_alll)

def send_alll(message):
    name_of_url[message.text] = message.text
    msg1 = bot.send_message(message.chat.id, 'Put url')
    bot.register_next_step_handler(msg1, send_all_userss)   

def send_all_userss(message):
    url_user_send[message.text] = message.text
    markup = types.InlineKeyboardMarkup()
    b1 = types.InlineKeyboardButton(name_of_url[message.text], url= url_user_send[message.text])
    markup.add(b1)
    keyboard_markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
    bot.send_message(message.chat.id, message_user_send, reply_markup=markup)
############################

但尝试使用name_of_url[message.text]作为按钮文本时出现错误,报错信息:

line 85, in send_all_userss
    b1 = types.InlineKeyboardButton(name_of_url[message.text], url= url_user_send[message.text])
                                    ~~~~~~~~~~~^^^^^^^^^^^^^^
KeyError: 'https://stackoverflow.com/questions/1871524/how-can-i-convert-json-to-csv'

若直接使用固定字符串作为按钮文本则可正常运行,预期实现效果是消息下方显示一个按钮,按钮文本为用户此前输入的内容。

问题原因

你用全局字典存储用户输入的逻辑完全错误:

  • 在name_of_link中,你把用户输入的主文本同时作为键和值存入message_user_send,后续也没有正确取出该值;
  • 在send_alll中,你把用户输入的按钮文本作为键和值存入name_of_url;
  • 到send_all_userss时,你拿当前用户输入的URL去name_of_url中查找键——但name_of_url的键是按钮文本,不是URL,自然找不到对应值,触发KeyError。

另外,全局字典还存在并发问题,多个用户同时使用时数据会互相覆盖。

正确解决方案

推荐使用用户会话存储每一步输入,或者通过register_next_step_handler传递参数,这里用会话的方式更规范:

修改后的代码(标准方案)

from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import CommandHandler, MessageHandler, Filters, ConversationHandler

# 定义会话状态
MAIN_TEXT, BUTTON_TEXT, BUTTON_URL = range(3)

@bot.message_handler(commands=['aaa'])
def start_add_button(message, update):
    msg = bot.send_message(message.chat.id, '输入消息主文本')
    return MAIN_TEXT

@bot.message_handler(func=lambda msg: True, state=MAIN_TEXT)
def get_main_text(message, update):
    # 将主文本存入当前用户的会话数据
    user_data = update.user_data
    user_data['main_text'] = message.text
    msg = bot.send_message(message.chat.id, '输入按钮显示文本')
    return BUTTON_TEXT

@bot.message_handler(func=lambda msg: True, state=BUTTON_TEXT)
def get_button_text(message, update):
    user_data = update.user_data
    user_data['button_text'] = message.text
    msg = bot.send_message(message.chat.id, '输入按钮跳转链接')
    return BUTTON_URL

@bot.message_handler(func=lambda msg: True, state=BUTTON_URL)
def send_final_message(message, update):
    user_data = update.user_data
    button_url = message.text
    
    # 构建带链接的按钮
    markup = InlineKeyboardMarkup()
    button = InlineKeyboardButton(user_data['button_text'], url=button_url)
    markup.add(button)
    
    # 发送最终消息
    bot.send_message(
        message.chat.id,
        user_data['main_text'],
        reply_markup=markup
    )
    # 结束会话
    return ConversationHandler.END

# 注册会话处理器
conv_handler = ConversationHandler(
    entry_points=[CommandHandler('aaa', start_add_button)],
    states={
        MAIN_TEXT: [MessageHandler(Filters.text & ~Filters.command, get_main_text)],
        BUTTON_TEXT: [MessageHandler(Filters.text & ~Filters.command, get_button_text)],
        BUTTON_URL: [MessageHandler(Filters.text & ~Filters.command, send_final_message)],
    },
    fallbacks=[],
)
bot.add_handler(conv_handler)

关键修改点

  1. 使用ConversationHandler管理多步输入流程,每个用户的输入独立存储在user_data中,不会互相干扰;
  2. 每一步输入都存入会话数据,最后统一取出使用,彻底避免KeyError;
  3. 流程符合Telegram Bot的标准开发模式,可读性和可维护性更强。

临时修复方案(无需重构架构)

如果暂时不想改用会话处理器,也可以调整全局字典的存储逻辑,用用户ID作为区分键:

# 全局字典,以用户ID为键存储各用户的输入
user_inputs = {}

@bot.message_handler(commands=['aaa'])
def send(message):
    user_id = message.chat.id
    user_inputs[user_id] = {}  # 初始化当前用户的存储容器
    msg1 = bot.send_message(user_id, 'Put main text')
    bot.register_next_step_handler(msg1, name_of_link)

def name_of_link(message):
    user_id = message.chat.id
    user_inputs[user_id]['main_text'] = message.text
    msg1 = bot.send_message(user_id, 'Put name of url')
    bot.register_next_step_handler(msg1, send_alll)

def send_alll(message):
    user_id = message.chat.id
    user_inputs[user_id]['button_text'] = message.text
    msg1 = bot.send_message(user_id, 'Put url')
    bot.register_next_step_handler(msg1, send_all_userss)   

def send_all_userss(message):
    user_id = message.chat.id
    user_inputs[user_id]['button_url'] = message.text
    
    markup = types.InlineKeyboardMarkup()
    b1 = types.InlineKeyboardButton(user_inputs[user_id]['button_text'], url=user_inputs[user_id]['button_url'])
    markup.add(b1)
    
    bot.send_message(user_id, user_inputs[user_id]['main_text'], reply_markup=markup)
    # 可选:删除用户数据,避免内存占用
    del user_inputs[user_id]

这个方案通过用户ID区分不同用户的输入,所有数据都存在对应用户的子字典中,最后直接取出对应字段即可,不会出现KeyError。

内容的提问来源于stack exchange,提问作者WinnieNotThePooh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 22:12:17