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

discord.py /leaderboard命令因成员退出服务器报错求助

解决Discord机器人排行榜命令因已离开服务器用户导致的AttributeError错误

问题描述

开发Discord机器人等级系统时,当排行榜上的成员退出所有机器人所在服务器后,/leaderboard命令会抛出AttributeError: 'NoneType' object has no attribute 'display_name'错误,导致命令完全失效。

问题原因

核心问题出在排行榜命令的这段代码:

member = ctx.guild.get_member(int(id))
embed.add_field(name=f"{pos+1} - {member.display_name} (@{member.name})", value=f"**Level {bal['level']}**\n{bal['experience']} XP", inline=False)

当用户退出服务器后,ctx.guild.get_member()无法在服务器成员缓存中找到该用户,会返回None,此时直接访问member.display_name就会触发AttributeError。

解决方案

方案1:兼容已离开用户,处理None值

修改leaderboard命令,增加对None值的判断,优先尝试通过Discord API获取用户基础信息,失败则显示用户ID:

@bot.tree.command(name="leaderboard", description="View the servers leaderboard. (Levels)")
async def hello(ctx: discord.Interaction):
    embed = discord.Embed(title=f"Leaderboard for {ctx.guild.name}", color=discord.Colour.blurple())
    with open('level.json', 'r') as file:
        data = json.load(file)
    data = data[str(ctx.guild.id)]
    sorted_data = sorted(data.items(), key = lambda item:item[1]['experience'], reverse=True)
    
    for pos, (id, bal) in enumerate(sorted_data):
        member = ctx.guild.get_member(int(id))
        # 处理已离开服务器的用户
        if member:
            display_name = member.display_name
            username = member.name
        else:
            # 尝试通过API获取用户信息
            try:
                user = await bot.fetch_user(int(id))
                display_name = user.name
                username = user.name
            except discord.NotFound:
                # 用户账号已删除,显示ID
                display_name = f"用户已离开(ID: {id})"
                username = f"ID: {id}"
        
        embed.add_field(name=f"{pos+1} - {display_name} (@{username})", value=f"**Level {bal['level']}**\n{bal['experience']} XP", inline=False)
        embed.set_footer(text="Pro tip: Use /level [user] to view more specific information about that member")
        if pos+1 > 9:
            break 
    
    await ctx.response.send_message(embed=embed)
    if debug_mode == True:
        print(f"Debug: {ctx.user.name} viewed {ctx.guild.name}'s leaderboard")
        if log_enabled == True:
            with open('botlog.log', 'a') as f:
                today = date.today()
                t = time.localtime()
                current_time = time.strftime("%H:%M:%S", t)
                f.write(f"\n{today} {current_time} [INFO] {ctx.user.name} viewed a servers leaderboard")

方案2:定期清理无效用户数据

添加后台任务,定期检查并删除数据库中已离开服务器的用户数据,从根源避免无效数据干扰:

import asyncio

async def cleanup_removed_users():
    while True:
        with open('level.json', 'r', encoding='utf-8') as f:
            users = json.load(f)
        
        for guild_id in list(users.keys()):
            guild = bot.get_guild(int(guild_id))
            if not guild:
                # 机器人已离开该服务器,删除整个服务器数据
                del users[guild_id]
                continue
            
            # 遍历服务器用户数据,清理已离开成员
            for user_id in list(users[guild_id].keys()):
                if not guild.get_member(int(user_id)):
                    del users[guild_id][user_id]
            
            # 服务器数据为空则删除条目
            if not users[guild_id]:
                del users[guild_id]
        
        with open('level.json', 'w', encoding='utf-8') as f:
            json.dump(users, f)
        
        # 每24小时执行一次清理
        await asyncio.sleep(86400)

# 机器人启动时启动清理任务
@bot.event
async def on_ready():
    print(f"Logged in as {bot.user}")
    bot.loop.create_task(cleanup_removed_users())

关键优化点

  • 使用await bot.fetch_user()突破服务器缓存限制,即使用户离开也能获取基础信息(需机器人拥有identify权限)
  • 增加异常处理,避免用户账号已删除导致的额外错误
  • 定期清理无效数据,减少数据库冗余,提升命令执行效率

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 02:19:54