如何让Python Discord Bot在提及非服务器成员时发送嵌入错误消息
Discord Bot赞美命令:处理不存在的服务器成员问题
问题描述
开发Python Discord Bot时,实现了!compliment命令用于给提及成员或调用者发送随机赞美。但当输入!compliment <不在服务器的用户名>时,终端会抛出MemberNotFound错误,而非在服务器内发送嵌入错误消息。需求是:先检查提及用户是否在当前服务器,若不在则向命令调用者发送红色嵌入错误提示。
现有代码
# (4) Compliment command. @commands.command( name = 'compliment', aliases = ['Compliment', 'COMPLIMENT'], description = 'Gives a random compliment.' ) async def compliment(self, ctx, *, member: discord.Member = None): try: await ctx.typing() response = random.choice(Compliments) if member is not None: if member.guild != ctx.guild: embed = discord.Embed( title = '__Error__', description = 'This member is not on this server.', color = discord.Color.red() ) await ctx.reply(embed = embed) else: embed = discord.Embed( title = '__Compliment__', description = f'{member.mention}, {response}', color = discord.Color.dark_blue() ) await ctx.reply(embed = embed) if member is None: embed = discord.Embed( title = '__Compliment__', description = f'{ctx.author.mention}, {response}', color = discord.Color.dark_blue() ) await ctx.reply(embed = embed) except Exception as e: print(f'An error occurred in compliment command: {e}')
报错信息
Traceback (most recent call last): File "C:\Users\xesch\AppData\Local\Programs\Python\Python312\Lib\site-packages\discord\ext\commands\bot.py", line 1350, in invoke await ctx.command.invoke(ctx) File "C:\Users\xesch\AppData\Local\Programs\Python\Python312\Lib\site-packages\discord\ext\commands\core.py", line 1021, in invoke await self.prepare(ctx) File "C:\Users\xesch\AppData\Local\Programs\Python\Python312\Lib\site-packages\discord\ext\commands\core.py", line 938, in prepare await self._parse_arguments(ctx) File "C:\Users\xesch\AppData\Local\Programs\Python\Python312\Lib\site-packages\discord\ext\commands\core.py", line 853, in _parse_arguments kwargs[name] = await self.transform(ctx, param, attachments) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\xesch\AppData\Local\Programs\Python\Python312\Lib\site-packages\discord\ext\commands\core.py", line 715, in transform return await run_converters(ctx, converter, argument, param) # type: ignore ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\xesch\AppData\Local\Programs\Python\Python312\Lib\site-packages\discord\ext\commands\converter.py", line 1355, in run_converters return await _actual_conversion(ctx, converter, argument, param) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\xesch\AppData\Local\Programs\Python\Python312\Lib\site-packages\discord\ext\commands\converter.py", line 1237, in _actual_conversion return await converter().convert(ctx, argument) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\xesch\AppData\Local\Programs\Python\Python312\Lib\site-packages\discord\ext\commands\converter.py", line 276, in convert raise MemberNotFound(argument) discord.ext.commands.errors.MemberNotFound: Member "@lakshey" not found.
问题原因
discord.Member转换器会在命令执行前尝试将输入的参数转换为服务器成员对象,如果找不到匹配成员,会直接抛出MemberNotFound异常,这个过程发生在代码中的try块之前,所以try-except无法捕获该错误。
解决方案
方法一:使用命令错误处理装饰器(推荐)
利用discord.py提供的命令错误处理机制,专门捕获MemberNotFound异常并发送嵌入错误消息,同时修复原代码中重复执行的逻辑问题:
# (4) Compliment command. @commands.command( name='compliment', aliases=['Compliment', 'COMPLIMENT'], description='Gives a random compliment.' ) async def compliment(self, ctx, *, member: discord.Member = None): await ctx.typing() response = random.choice(Compliments) if member is not None: # 经过转换器验证后,member必然属于当前服务器,此判断可省略 if member.guild != ctx.guild: embed = discord.Embed( title='__Error__', description='This member is not on this server.', color=discord.Color.red() ) await ctx.reply(embed=embed) else: embed = discord.Embed( title='__Compliment__', description=f'{member.mention}, {response}', color=discord.Color.dark_blue() ) await ctx.reply(embed=embed) elif member is None: embed = discord.Embed( title='__Compliment__', description=f'{ctx.author.mention}, {response}', color=discord.Color.dark_blue() ) await ctx.reply(embed=embed) # 命令专属错误处理函数 @compliment.error async def compliment_error(ctx, error): if isinstance(error, commands.MemberNotFound): embed = discord.Embed( title='__Error__', description='This member is not on this server.', color=discord.Color.red() ) await ctx.reply(embed=embed) else: print(f'An error occurred in compliment command: {error}')
方法二:手动处理成员查找
如果需要更灵活的成员匹配逻辑,可以接收字符串参数,自行在服务器内查找成员:
# (4) Compliment command. @commands.command( name='compliment', aliases=['Compliment', 'COMPLIMENT'], description='Gives a random compliment.' ) async def compliment(self, ctx, *, member_str: str = None): await ctx.typing() response = random.choice(Compliments) if member_str is not None: member = None # 处理用户提及格式(如<@123456>) if member_str.startswith('<@') and member_str.endswith('>'): user_id = member_str.strip('<@!>') try: member = ctx.guild.get_member(int(user_id)) except ValueError: pass # 按用户名查找 if not member: member = discord.utils.get(ctx.guild.members, name=member_str) # 按昵称查找 if not member: member = discord.utils.get(ctx.guild.members, display_name=member_str) if not member: # 未找到成员,发送错误消息 embed = discord.Embed( title='__Error__', description='This member is not on this server.', color=discord.Color.red() ) await ctx.reply(embed=embed) return # 找到成员,发送赞美 embed = discord.Embed( title='__Compliment__', description=f'{member.mention}, {response}', color=discord.Color.dark_blue() ) await ctx.reply(embed=embed) else: # 未提及成员,给调用者发赞美 embed = discord.Embed( title='__Compliment__', description=f'{ctx.author.mention}, {response}', color=discord.Color.dark_blue() ) await ctx.reply(embed=embed)
说明
- 方法一遵循discord.py的设计规范,代码简洁易维护,是优先推荐的方案。
- 方法二适合需要自定义成员匹配逻辑的场景,但需要自行处理各种成员标识格式。
内容的提问来源于stack exchange,提问作者Xeschoz
相关产品推荐
相关产品推荐

