Discord机器人获取公会成员信息报KeyError及实现服务器金币Top10榜单问题
问题1:KeyError报错修复
报错原因
- 公会配置数据和用户金币数据被混存在同一个
mainbank.json文件中,存储结构互相冲突 on_guild_join事件存在语法错误:写入文件时"w"参数位置错误,且直接尝试序列化Discord频道对象(JSON格式不支持序列化Discord原生对象)- 当前触发命令的公会是机器人添加
on_guild_join事件前就加入的,没有触发过数据写入逻辑,因此JSON中不存在对应公会ID的键 guild命令中直接将频道对象作为embed参数发送,类型不匹配,即便解决KeyError也会触发新的报错
修复代码
首先拆分存储文件,新增guild_config.json专门存储公会配置,修改后的代码如下:
# 初始化guild_config.json,文件不存在时自动创建空配置 import os if not os.path.exists("guild_config.json"): with open("guild_config.json", "w") as f: json.dump({}, f) @client.event async def on_guild_join(guild): with open("guild_config.json", "r") as f: guildInfo = json.load(f) # 存储频道ID而非频道对象,避免序列化失败 guildInfo[str(guild.id)] = guild.text_channels[0].id # 修复写入语法错误 with open("guild_config.json", "w") as f: json.dump(guildInfo, f) @client.command(aliases = ['gd']) async def guild(ctx): with open("guild_config.json", "r") as f: guildInfo = json.load(f) # 增加键不存在的容错处理 guild_id = str(ctx.guild.id) if guild_id not in guildInfo: # 无配置时默认使用命令触发的当前频道 channel = ctx.channel else: channel = client.get_channel(guildInfo[guild_id]) # 自行调整embed内容即可 em = discord.Embed(title="公会配置", description=f"绑定的通知频道为{channel.mention}") await ctx.send(embed=em)
问题2:排行榜修改为仅展示当前公会前10名
前置配置
首先需要开启成员意图,否则无法获取公会完整成员列表:
- 代码层面开启意图:
intents = discord.Intents.default() intents.members = True # 替换为你原来的前缀初始化机器人 client = commands.Bot(command_prefix='你的命令前缀', intents=intents)
- 进入Discord开发者后台的Bot设置页,开启
Server Members Intent开关。
修改后的排行榜代码
同时修复了原排行榜同金额用户数据被覆盖的问题:
@client.command(aliases = ["lb"]) async def leaderboard(ctx, x = 10): users = await get_bank_data() # 获取当前公会所有成员ID集合,转成字符串匹配JSON的键格式 guild_member_ids = {str(member.id) for member in ctx.guild.members} leader_board = [] for user_id in users: # 仅统计当前公会内的成员 if user_id not in guild_member_ids: continue total_amount = users[user_id]["wallet"] + users[user_id]["bank"] leader_board.append((total_amount, user_id)) # 按总资产降序排序 leader_board = sorted(leader_board, key=lambda x: x[0], reverse=True) em = discord.Embed(title = f"<:emoji_23:886988033872764938> : 本公会富豪榜TOP {x}" , description = "排名依据为钱包+银行总资产",color = discord.Color(0x00FFFC)) index = 1 for amt, id_ in leader_board: member = ctx.guild.get_member(int(id_)) # 兼容成员已离开公会的异常情况 if not member: continue name = member.display_name em.add_field(name = f"{index}. {name}" , value = f"「总资产」❯❯ {amt} 🪙", inline = False) if index == x: break index += 1 await ctx.send(embed = em)
内容的提问来源于stack exchange,提问作者Hiresh Verma
相关产品推荐
相关产品推荐

