Python 3.x discord.py机器人Purge命令仅测试服可用问题排查
Discord机器人Purge命令跨服务器报错问题排查与修复
问题背景
使用discord.py v2.2.3 + Python 3.11.3开发的Discord机器人,Purge(消息清理)命令在测试服务器运行正常,但在其他服务器仅成功过一两次,现在调用必触发错误提示。
相关代码
clean_message方法
async def clean_message(self, interaction: Interaction, amount: int, check: Callable) -> Any: if isinstance((channel := interaction.channel), (CategoryChannel, ForumChannel, PartialMessageable)): return assert channel is not None try: msgs = [ m async for m in channel.history( limit=300, before=Object(id=interaction.id), after=None ) if check(m) == True and UTC.localize((datetime.now() - timedelta(days=365))) <= m.created_at # default 14 ][:amount] await channel.delete_messages(msgs) except Exception as e: msg = await self.bot.error( f"I'm sorry, I am unable to purge messages in **{channel}**!", interaction ) if msg: await msg.delete(delay=5) else: if len(msgs) < 1: msg = await self.bot.error( f"No messages found in **{channel}**!", interaction ) if msg: await msg.delete(delay=5) else: msg = await self.bot.success( f"Succesfully purged **{len(msgs)}** messages from **{channel}**!", interaction ) if msg: await msg.delete(delay=5)
Purge命令调用代码
@app_commands.command( name='purge', description="Purges messages in channel" ) @app_commands.default_permissions(manage_messages=True) @app_commands.describe( amount='Amount of messages to purge (Default: 20)', user='Only purge messages by user', content='Only purge messages by content' ) async def purge_command(self, interaction: Interaction, amount: Optional[int], user: Optional[User], content: Optional[str]): if not amount: amount = 20 if amount < 1: return await self.bot.error("Can't purge messages! Amount too small!", interaction) if amount > 150: return await self.bot.error("Can't purge messages! Amount too Large!", interaction) if user == None and content == None: def check(x): return x.pinned == False else: if user != None and content != None: def check(x): return x.author.id == user.id and x.content.lower( ) == content.lower() and x.pinned == False elif user != None and content == None: def check(x): return x.author.id == user.id and x.pinned == False else: assert content is not None def check(x): return x.conetent.lower( ) == content.lower() and x.pinned == False await interaction.response.defer() await self.clean_message( interaction=interaction, amount=amount, check=check )
问题排查与修复方案
1. 修复拼写错误
在purge_command的最后一个check函数里,x.conetent是拼写错误,应改为x.content。这个错误会直接触发AttributeError,导致命令执行失败。
2. 修正时间判断逻辑
Discord API仅允许删除14天以内的消息,代码中写的365天会导致尝试删除超期消息时触发API错误。同时:
datetime.now()获取的是本地时间,而Discord消息的created_at是UTC时间,需改用datetime.utcnow()避免时区偏差- 无需使用
UTC.localize,utcnow()返回的已是UTC时区的datetime对象
修改后的时间判断条件:
datetime.utcnow() - timedelta(days=14) <= m.created_at
3. 优化异常处理,暴露具体错误
当前异常处理仅返回通用提示,无法得知具体错误原因(如权限不足、消息超期、空列表删除等)。建议在except块中打印错误信息:
except Exception as e: print(f"Purge错误详情: {str(e)}") # 打印错误到控制台 msg = await self.bot.error( f"I'm sorry, I am unable to purge messages in **{channel}**!\n错误详情: {str(e)}", interaction ) if msg: await msg.delete(delay=5)
4. 避免删除空消息列表
当没有符合条件的消息时,msgs会是空列表,调用channel.delete_messages(msgs)会触发API错误。需在删除前判断列表是否为空:
if msgs: await channel.delete_messages(msgs) else: raise ValueError("没有可删除的消息")
5. 确认机器人权限
确保机器人在目标服务器拥有以下权限:
- 管理消息(Manage Messages):用于删除消息
- 查看消息历史(Read Message History):用于获取频道消息历史
6. 优化check函数写法(可选)
合并重复逻辑,让代码更简洁:
def check(x): if x.pinned: return False if user and x.author.id != user.id: return False if content and x.content.lower() != content.lower(): return False return True
修复后关键代码示例
修正后的purge_command检查函数
else: assert content is not None def check(x): return x.content.lower() == content.lower() and x.pinned == False
修正后的clean_message时间判断与空列表处理
msgs = [ m async for m in channel.history( limit=300, before=Object(id=interaction.id), after=None ) if check(m) and datetime.utcnow() - timedelta(days=14) <= m.created_at ][:amount] if msgs: await channel.delete_messages(msgs) else: raise ValueError("未找到符合条件的消息")
内容的提问来源于stack exchange,提问作者Frank Austin
相关产品推荐
相关产品推荐

