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

Discord.py 开发 giveaway 抽奖指令后未显示参与反应的问题求解

Discord.py 抽奖指令反应不显示问题修复

核心根因定位

  • 变量赋值逻辑错误:原代码中my.msg = await ctx.send(embed=embed)的写法,是尝试给一个从未定义的my对象的msg属性赋值,Python运行到这行就会直接抛出NameError中断指令执行,后续添加反应的代码根本不会被运行,自然看不到参与表情。
  • 反应添加流程无异常兜底:就算修正了赋值问题,如果bot没有对应频道的添加反应权限、输入的自定义emoji无法识别,add_reaction的报错会直接中断流程,后台报错不会同步到聊天频道,用户会误以为反应加载失败。
  • 时长参数逻辑错位:原代码传入的mins是分钟单位,但asyncio.sleep()的计时单位是秒,原代码直接把分钟数传给sleep方法,会导致实际等待时长远短于设定的抽奖时长。
  • 反应读取逻辑不严谨:直接取reactions[0]的写法,一旦消息无反应、或者后续追加了其他反应,就会触发索引越界、读错反应对象的问题。

修复后的可运行代码

import discord
import asyncio
import random
import datetime
from discord.ext import commands

# 按实际需求配置intents
intents = discord.Intents.default()
intents.message_content = True
bot = commands.Bot(command_prefix="!", intents=intents)

@bot.command()
@commands.has_role("Admin")
async def gstart(ctx, mins: int, *, prize: str):
    if mins <= 0:
        await ctx.send("抽奖时长不能小于等于0")
        return

    embed = discord.Embed(
        title="🎉 抽奖活动开启",
        description=f"点击下方🎉表情即可参与抽奖\n奖品:**{prize}**",
        color=discord.Color.gold()
    )
    end_time = datetime.datetime.utcnow() + datetime.timedelta(minutes=mins)
    embed.add_field(name="开奖时间(UTC)", value=end_time.strftime("%Y-%m-%d %H:%M:%S"), inline=False)
    embed.set_footer(text=f"发起人:{ctx.author.display_name}")

    # 直接将发送的消息对象赋值给自定义变量,替换原错误的对象属性赋值
    giveaway_msg = await ctx.send(embed=embed)

    # 给消息加反应,捕获常见报错做提示
    try:
        await giveaway_msg.add_reaction("🎉")
    except discord.Forbidden:
        await ctx.send("当前缺少在该频道添加反应的权限,请调整bot权限后重试")
        return
    except Exception as e:
        await ctx.send(f"添加参与反应失败:{str(e)}")
        return

    # 按秒数换算等待时长,避免单位错位
    await asyncio.sleep(mins * 60)

    latest_msg = await ctx.channel.fetch_message(giveaway_msg.id)
    # 精准匹配🎉对应的反应对象,不依赖列表顺序
    target_reaction = discord.utils.get(latest_msg.reactions, emoji="🎉")

    if not target_reaction:
        await ctx.send("未检测到抽奖参与反应,开奖失败")
        return

    participants = await target_reaction.users().flatten()
    # 过滤掉bot自身的账号
    participants = [user for user in participants if not user.bot]

    if not participants:
        await ctx.send("没有用户参与本次抽奖,无法产生中奖者")
        return

    winner = random.choice(participants)
    await ctx.send(f"🎊 恭喜 {winner.mention} 抽中奖品:{prize}!")


@bot.command()
@commands.has_permissions(kick_members=True)
async def reroll(ctx, channel: discord.TextChannel, message_id: int):
    try:
        giveaway_msg = await channel.fetch_message(message_id)
    except discord.NotFound:
        await ctx.send("找不到对应ID的消息,请确认消息ID正确、bot有对应频道的查看权限")
        return

    target_reaction = discord.utils.get(giveaway_msg.reactions, emoji="🎉")
    if not target_reaction:
        await ctx.send("该消息未找到🎉参与反应,无法重抽")
        return

    participants = await target_reaction.users().flatten()
    participants = [user for user in participants if not user.bot]

    if not participants:
        await ctx.send("没有有效参与用户,无法重抽")
        return

    new_winner = random.choice(participants)
    await channel.send(f"🎊 重抽结果:恭喜 {new_winner.mention} 获得奖品!")

部署注意事项

  • 确保bot在目标频道开启「发送消息」「添加反应」「读取消息历史」的基础权限,否则反应逻辑无法触发。
  • 代码中的指令前缀!需替换为你自己设置的bot命令前缀。
  • 长时长抽奖不建议单纯依赖asyncio.sleep逻辑,bot重启会丢失正在进行的抽奖任务,可搭配数据库存储抽奖状态实现持久化。

内容的提问来源于stack exchange,提问作者Sarvesh Jagtap

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.24 02:24:01