
本文详解如何通过 telegram bot api 实时监听和获取群组投票的完整结果,包括总票数、各选项得票数,以及非匿名投票下用户投票记录的捕获与存储方法。
本文详解如何通过 telegram bot api 实时监听和获取群组投票的完整结果,包括总票数、各选项得票数,以及非匿名投票下用户投票记录的捕获与存储方法。
Telegram Bot 提供了完善的投票支持能力,但获取投票结果并非“一键查询”,而是依赖事件驱动机制。核心在于正确理解并利用两类关键更新类型:poll 和 poll_answer。
✅ 获取最终投票结果:调用 stopPoll 即可返回完整数据
当你已通过 sendPoll 发起投票并保存了 chat_id 与 message_id 后,无需持续轮询或监听 Update.poll —— 最简洁可靠的方式是主动调用 stopPoll 接口。该接口不仅立即结束投票,还会同步返回包含全部统计信息的 Poll 对象:
import requests
def stop_poll(bot_token, chat_id, message_id):
url = f"https://api.telegram.org/bot{bot_token}/stopPoll"
data = {
"chat_id": chat_id,
"message_id": message_id
}
response = requests.post(url, data=data, timeout=15)
if response.status_code == 200:
result = response.json()
if result.get("ok"):
poll = result["result"]
print(f"总投票人数: {poll['total_voter_count']}")
for i, option in enumerate(poll["options"]):
print(f"选项 {i+1} '{option['text']}': {option['voter_count']} 票")
return poll
else:
print("API 响应失败:", result.get("description"))
else:
print("HTTP 请求失败:", response.status_code)
return None
# 示例调用
BOT_TOKEN = "YOUR_BOT_TOKEN"
CHAT_ID = -1001234567890 # 注意:群组需为超级群(supergroup),chat_id 以 -100 开头
MESSAGE_ID = 12345
stop_poll(BOT_TOKEN, CHAT_ID, MESSAGE_ID)
✅ 返回的 Poll 对象中已包含:
- total_voter_count: 总参与投票人数(含重复投票者,Telegram 允许单用户多次投票,但仅最后一次有效);
- options: 每个选项的 text 和 voter_count(最终有效票数);
- is_closed: 值为 True,确认已关闭;
- id: 与你发送时一致的 poll_id,可用于关联。
⚠️ 注意:stopPoll 仅适用于你创建的投票(即 bot 是发起者),且目标消息必须存在于可访问的群组/频道中;普通群组(非 supergroup)不支持投票功能。
✅ 获取用户级投票明细:监听 poll_answer 更新(仅限非匿名投票)
若需记录“谁投了哪一票”,必须满足两个前提:
- 创建投票时设置 is_anonymous=False(默认为 True);
- 主动监听 poll_answer 类型的更新(allowed_updates=["poll_answer"])。
Telegram 不会保留历史投票记录 —— poll_answer 是瞬时事件,错过即不可恢复。因此需实时接收并持久化:
import requests
import time
def fetch_poll_answers(bot_token, offset=0):
url = f"https://api.telegram.org/bot{bot_token}/getUpdates"
params = {
"offset": offset,
"allowed_updates": ["poll_answer"],
"timeout": 30
}
response = requests.get(url, params=params, timeout=35)
return response.json() if response.status_code == 200 else None
def handle_poll_answer(answer):
user = answer["user"]
poll_id = answer["poll_id"]
option_ids = answer["option_ids"] # list[int],对应 options 索引
# 示例:存入数据库(伪代码)
# db.save_vote(poll_id=poll_id, user_id=user["id"], username=user.get("username"),
# option_indices=option_ids, timestamp=answer["update_id"])
# 长轮询示例(生产环境建议改用 Webhook)
BOT_TOKEN = "YOUR_BOT_TOKEN"
last_update_id = 0
while True:
res = fetch_poll_answers(BOT_TOKEN, offset=last_update_id + 1)
if res and res.get("ok"):
for update in res["result"]:
if "poll_answer" in update:
handle_poll_answer(update["poll_answer"])
last_update_id = max(last_update_id, update["update_id"])
time.sleep(1)
? 关键字段说明(见 PollAnswer):
- poll_id: 关联原始投票,用于区分不同问卷;
- user: 投票用户对象(含 id, first_name, username 等);
- option_ids: 用户选择的选项索引列表(多选题可能含多个值);
- update_id: 全局唯一递增 ID,用于避免重复处理。
? 最佳实践总结
| 场景 | 推荐方式 | 补充说明 |
|---|---|---|
| 仅需最终统计结果 | 调用 stopPoll | 简洁、可靠、无状态依赖;推荐作为标准流程 |
| 需用户粒度分析 | 实时监听 poll_answer + is_anonymous=False | 必须自行设计存储逻辑;无法回溯历史答案 |
| 实时监控投票进度 | 监听 Update.poll(可选) | 用于显示动态计票 UI,但最终仍需 stopPoll 获取权威结果 |
? 小贴士:
- 所有投票操作均要求 bot 在目标群组中具有 can_manage_topics(频道)或 can_manage_chat(群组)权限;
- 使用 Webhook 替代 getUpdates 可显著降低延迟与服务器负载;
- 多选题(type="quiz" 除外)的 option_ids 为整数列表,注意前端渲染时映射到实际选项文本。
通过合理组合 stopPoll 与 poll_answer 事件,你的 Telegram Bot 即可构建出专业、可审计、支持深度分析的投票系统。











