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
相关产品推荐
相关产品推荐

