如何在Python的Telebot中根据用户选择控制schedule定时推送?
Telegram机器人订阅推送功能:正确管理schedule定时任务
原代码存在几个核心问题,导致无法正常实现订阅/取消功能:
- 回调函数内的
while True死循环会阻塞TeleBot主事件循环,机器人彻底无法响应其他请求 - 任务创建、取消的逻辑写在死循环之后,永远不会被执行
- 没有针对用户ID存储任务实例,无法独立管理不同用户的订阅状态
- 存在未定义的
godo()函数调用错误
修正后的实现方案
以下是可以正常运行的代码,解决了上述所有问题:
import telebot import schedule import time from telebot import types from threading import Thread # 替换成你的机器人Token bot = telebot.TeleBot("YOUR_BOT_TOKEN") # 存储用户的定时任务:键为用户chat_id,值为schedule任务实例 user_jobs = {} def run_schedule(): """单独线程运行schedule调度,避免阻塞主bot""" while True: schedule.run_pending() time.sleep(1) # 启动schedule后台线程 Thread(target=run_schedule, daemon=True).start() def send_daily_push(chat_id): """每日推送消息的核心函数""" try: bot.send_message(chat_id, "每日书籍推荐推送来啦!") except Exception as e: print(f"推送失败:{str(e)}") # 若用户拉黑机器人,自动移除任务 if chat_id in user_jobs: schedule.cancel_job(user_jobs[chat_id]) del user_jobs[chat_id] @bot.message_handler(func=lambda message: message.text == "Подборка книг") def handle_book_request(message): # 构建订阅选择按钮 podborka = types.InlineKeyboardMarkup() yes_btn = types.InlineKeyboardButton("Да", callback_data="да") no_btn = types.InlineKeyboardButton("Нет", callback_data="нет") podborka.add(yes_btn, no_btn) bot.send_message(message.chat.id, "Получать рассылку?", reply_markup=podborka) @bot.callback_query_handler(func=lambda call: True) def handle_subscription_callback(call): chat_id = call.message.chat.id if call.data == "да": # 用户选择订阅,先检查是否已有任务 if chat_id not in user_jobs: # 这里设置定时规则,测试用每10秒推送一次,正式环境可改为每日固定时间 # job = schedule.every().day.at("10:00").do(send_daily_push, chat_id=chat_id) job = schedule.every(10).seconds.do(send_daily_push, chat_id=chat_id) user_jobs[chat_id] = job bot.send_message(chat_id, "订阅成功!每日推送已开启🔔") else: bot.send_message(chat_id, "你已经订阅过推送啦!") elif call.data == "нет": # 用户选择取消订阅,检查是否存在任务 if chat_id in user_jobs: schedule.cancel_job(user_jobs[chat_id]) del user_jobs[chat_id] bot.send_message(chat_id, "推送已关闭❌") else: bot.send_message(chat_id, "你还没有订阅推送哦!") # 标记回调查阅完成,避免Telegram重复发送回调 bot.answer_callback_query(call.id) # 启动机器人 bot.polling(none_stop=True)
关键逻辑说明
- user_jobs字典:精准记录每个用户的定时任务,确保可以独立管理单个用户的订阅状态,不会互相干扰
- 后台线程运行schedule:把schedule的循环放到单独线程,彻底避免阻塞TeleBot的主事件循环,机器人可以正常处理所有消息和回调
- 推送异常处理:加入捕获推送失败的逻辑,若用户拉黑机器人,自动移除对应任务,避免无效报错
- 回调反馈:给用户明确的操作反馈,同时标记回调查阅完成,符合Telegram API规范
内容的提问来源于stack exchange,提问作者able
相关产品推荐
相关产品推荐

