引言
在Telegram群组管理中,投票是收集成员意见、组织活动的常用功能。Telegram原生支持Poll(投票)消息,但有时我们需要更灵活的自定义选项、实时统计和推送结果。通过Telegram Bot API,我们可以开发一个智能机器人,让投票过程自动化,结果实时更新并推送给群成员。本文将介绍两种实现方式:利用原生Poll快速创建,以及通过内联键盘开发自定义投票系统,并重点演示如何实时推送结果。
准备工作:创建机器人和获取Token
开始之前,你需要一个Telegram机器人。在Telegram中搜索BotFather,发送新机器人指令,获取API Token。确保已安装Python和python-telegram-bot库:
pip install python-telegram-bot编写代码前,导入库并初始化应用:
from telegram.ext import Application, CommandHandler, CallbackQueryHandler, PollAnswerHandler
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
import logging
TOKEN = "你的TOKEN"
app = Application.builder().token(TOKEN).build()方案一:使用原生Poll发送群组投票
Telegram Bot API 提供了sendPoll方法,可以直接发送投票消息,支持单选/多选、匿名、选项自定义。当成员投票后,机器人会收到PollAnswer更新,我们可以实时获取投票状态,并在投票结束后将结果推送到群里。
发送Poll
async def start_poll(update: Update, context):
chat_id = update.effective_chat.id
question = "你最喜欢哪个编程语言?"
options = ["Python", "JavaScript", "Go", "Rust"]
message = await context.bot.send_poll(
chat_id=chat_id,
question=question,
options=options,
is_anonymous=False, # 匿名投票
allows_multiple_answers=False
)
# 可以存储poll_id用于后续操作
context.bot_data['poll_id'] = message.poll.id
app.add_handler(CommandHandler("poll", start_poll))监听投票响应并推送结果
注册PollAnswerHandler,在用户投票后触发,我们可以查询当前结果,并更新一条消息显示统计。但原生Poll的结果在客户端会自动展示,无需机器人额外处理。若希望投票结束后自动推送结果,可以设置一个定时任务,在Poll关闭后调用stopPoll获取最终结果,然后发送到群聊。
async def handle_poll_answer(update: Update, context):
poll_answer = update.poll_answer
poll_id = poll_answer.poll_id
# 这里可以记录用户选项,或查询更新后的状态
# 例如,使用bot_data缓存投票状态,并编辑消息实时展示
print(f"用户 {poll_answer.user.id} 投票")
app.add_handler(PollAnswerHandler(handle_poll_answer))这种方案简单可靠,但定制性有限。若需要自定义选项或动态结果推送,我们更推荐下面的方案。
方案二:自定义内联键盘投票与实时推送
通过内联键盘,我们可以完全控制投票逻辑。机器人在群聊中发送一条包含按钮的消息,每个按钮代表一个选项。点击按钮后,回调数据处理程序更新投票统计,并编辑原消息,实时刷新结果。同时,我们可以设定结束后推送一条汇总消息。
发送自定义投票
async def send_custom_poll(update: Update, context):
chat_id = update.effective_chat.id
question = "你最喜欢哪个编程语言?"
options = ["Python", "JavaScript", "Go", "Rust"]
keyboard = [[InlineKeyboardButton(opt, callback_data=f"vote_")] for i, opt in enumerate(options)]
reply_markup = InlineKeyboardMarkup(keyboard)
await context.bot.send_message(
chat_id=chat_id,
text=f"📊 \n\n点击下方按钮参与投票:",
reply_markup=reply_markup
)
# 初始化投票状态,存储到bot_data或数据库中
context.bot_data['votes'] = {i: 0 for i in range(len(options))}
context.bot_data['users_voted'] = set()处理回调并实时更新
async def button_handler(update: Update, context):
query = update.callback_query
await query.answer()
user_id = query.from_user.id
if user_id in context.bot_data['users_voted']:
await query.edit_message_text("⚠️ 你已经投过票了!", show_alert=True)
return
choice = int(query.data.split('_')[1])
context.bot_data['votes'][choice] += 1
context.bot_data['users_voted'].add(user_id)
# 构建结果文本
total = sum(context.bot_data['votes'].values())
result_text = f"📊 投票结果(已有人参与)\n"
options = ["Python", "JavaScript", "Go", "Rust"]
for i, count in context.bot_data['votes'].items():
percent = count / total * 100 if total else 0
result_text += f"\n{options[i]}: 票 ({percent:.1f}%)"
# 编辑原消息,实时推送最新结果
keyboard = [[InlineKeyboardButton(opt, callback_data=f"vote_")] for i, opt in enumerate(options)]
await query.edit_message_text(
text=f"📊 投票进行中\n",
reply_markup=InlineKeyboardMarkup(keyboard)
)设置投票截止并自动推送最终结果
很多场景需要限制投票时间。我们可以使用定时任务(如asyncio.sleep)在指定时间后结束投票,发送最终统计结果。在按钮处理中,我们还可以加入“结束投票”的管理员专属按钮。下面给出一个简单实现:
async def end_vote(update: Update, context):
# 管理员指令触发
votes = context.bot_data.get('votes')
if votes is None:
await update.message.reply_text("当前没有投票")
return
result_text = "🔔 投票截止!最终结果:\n"
options = ["Python", "JavaScript", "Go", "Rust"]
for i, count in votes.items():
result_text += f"\n{options[i]}: 票\n"
await context.bot.send_message(update.effective_chat.id, result_text)
context.bot_data['votes'] = None
app.add_handler(CommandHandler("endvote", end_vote))除了手动结束,也可以利用JobQueue设置自动截止时间,然后推送结果。
部署与注意事项
- 数据持久化:机器人重启会丢失投票数据,建议将投票状态保存到Redis或SQLite中。
- 防止刷票:以上示例用集合记录已投票用户,但多机器人群组中可能无法完全准确。可以结合用户ID和群组ID,存入数据库。
- 实时推送频率:如果群组活跃,每次点击都编辑消息可能造成API频率限制。可以设置节流,如2秒内合并多次更新。
- 原生Poll的局限:原生Poll选项最多10个,且结果只展示比例,不显示人数。若需要详细数据,自定义方案更合适。
总结
通过Telegram Bot API,我们可以灵活地实现群组投票并实时推送结果。原生Poll适合快速创建,而基于内联键盘的自定义方案提供了更高的可控性,能够满足复杂场景。本文的代码示例可以直接运行于python-telegram-bot v20+环境。根据你的需求选择方案,并配合持久化与定时任务,即可打造一个专业的群组投票机器人。