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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 00:06:06