如何让Telegram Bot中两个调用API的函数同时运行?
问题描述
我开发了一个Telegram机器人,处理聊天命令的代码如下:
def runBot(): bot.polling(none_stop=True, interval=1, timeout=30, long_polling_timeout=65)
获取所有新消息(机器人已加入部分群组)的代码如下:
def getUpdates(): ... MethodGetUpdates = f'https://api.telegram.org/bot{BOT_TOKEN}/getUpdates' offsetParam = {'offset': offset, 'allowed_updates': ['message']} response = requests.get(MethodGetUpdates, offsetParam) ...
(我会自行计算offset参数)
但这两部分只能单独运行,无法同时工作。我尝试用多线程解决,编写了如下代码:
def runBot(): bot.polling(none_stop=True, interval=1, timeout=30, long_polling_timeout=65) def runScheluders(): schedule.every(70).seconds.do(getUpdates) if __name__ == "__main__": t1 = threading.Thread(target=runBot) t2 = threading.Thread(target=runScheluders) t1.start() t2.start()
但该方案无效:机器人能正常响应命令,但getUpdates无法获取新消息,返回结果为:
{'ok': True, 'result': []}
单独运行任意一部分都能正常工作,请问如何让两者同时运行?
解决方案
问题核心是Telegram Bot的polling方法本身就是基于getUpdates实现的:当你启动bot.polling()后,它会自动持续调用getUpdates并更新offset值,导致你手动写的getUpdates因为offset落后,永远拿不到已经被polling进程处理过的新消息。
给你两种可行的解决思路:
思路1:统一用polling处理所有消息
直接在polling的消息处理逻辑里同时处理命令和其他消息,不需要额外开线程调用getUpdates。以python-telegram-bot库为例:
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters def handle_start_command(update, context): update.message.reply_text('收到/start命令!') def handle_all_messages(update, context): # 这里处理所有非命令的消息,包括群组消息 chat_info = f"[{update.message.chat.title or update.message.chat.id}]" print(f"{chat_info} 收到消息:{update.message.text}") def runBot(): updater = Updater(BOT_TOKEN, use_context=True) dp = updater.dispatcher # 注册命令处理器 dp.add_handler(CommandHandler("start", handle_start_command)) # 注册普通消息处理器(排除命令消息) dp.add_handler(MessageHandler(Filters.text & ~Filters.command, handle_all_messages)) # 启动轮询 updater.start_polling(none_stop=True, interval=1, timeout=30, long_polling_timeout=65) updater.idle() if __name__ == "__main__": runBot()
思路2:完全自行实现轮询逻辑
如果一定要分开处理,就不要用库自带的polling,自己用线程实现完整的getUpdates轮询,同时处理命令和消息:
import requests import time BOT_TOKEN = "你的机器人Token" offset = 0 def send_reply(chat_id, text): url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage" requests.post(url, data={'chat_id': chat_id, 'text': text}) def process_single_update(update): message = update.get('message', {}) text = message.get('text', '') chat_id = message.get('chat', {}).get('id') if not chat_id: return # 处理命令 if text.startswith('/'): command = text.split()[0] if command == '/start': send_reply(chat_id, "收到启动命令!") # 处理普通消息 else: print(f"群组/私聊消息:{text}") def getUpdates_loop(): global offset while True: url = f'https://api.telegram.org/bot{BOT_TOKEN}/getUpdates' params = { 'offset': offset, 'allowed_updates': ['message'], 'timeout': 60 # 长轮询超时 } response = requests.get(url, params=params) result = response.json() if result['ok']: for update in result['result']: process_single_update(update) # 更新offset,确保下次只拿新消息 if update['update_id'] >= offset: offset = update['update_id'] + 1 time.sleep(1) if __name__ == "__main__": getUpdates_loop()
补充:你的原方案为什么无效?
bot.polling()会自动推进offset,导致你手动调用的getUpdates永远拿不到新消息;- 你的
runScheluders函数只定义了任务,但没有启动schedule的循环——需要加上while True: schedule.run_pending(); time.sleep(1)才会执行定时任务,但就算加上,也会因为offset被polling占用而无法获取消息。
内容的提问来源于stack exchange,提问作者Ivan
相关产品推荐
相关产品推荐

