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

如何修改Discord bot代码实现snipe捕获clear命令删除的前2条消息

问题根因

你当前的代码存在两个核心问题导致无法捕获clear指令删除的消息:

  • 批量删除消息时(discord.py中purge类方法执行的删除操作)默认触发on_bulk_message_delete事件,不会触发单条删除的on_message_delete,你的代码没有监听该事件
  • 每个频道仅存储最后一条被删消息,clear指令执行时最后删除的是$clear 2这条指令消息,直接覆盖了前面被删的普通用户消息,所以snipe只能拿到已经被删的指令内容,没有有效信息
  • 用await sleep(60)后删除存储条目的逻辑存在协程堆积、覆盖后删除异常的问题,稳定性差

注意:需要在Discord开发者后台开启Bot的Message Content Intent权限,否则无法正常读取消息内容。

修改后的完整代码

import discord
from discord.ext import commands
import time
from collections import defaultdict

# 存储结构改为每个频道存一个列表,每个元素是(作者, 内容, 删除时间戳, 是否是bot指令消息)
snipe_store = defaultdict(list)
# 最多存每个频道最近10条被删消息,可自行调整
MAX_SNIPE_PER_CHANNEL = 10
# 被删消息保留时间,单位秒
SNIPE_EXPIRE_TIME = 60

ult = commands.Bot(command_prefix='$', intents=discord.Intents.all())

# 清理过期消息的工具函数
def clean_expired(channel_id):
    now = time.time()
    snipe_store[channel_id] = [
        item for item in snipe_store[channel_id]
        if now - item[2] < SNIPE_EXPIRE_TIME
    ]

@ult.event
async def on_message_delete(message):
    # 忽略自己发的snipe返回消息,可根据需求调整
    if message.author == ult.user:
        return
    channel_id = message.channel.id
    # 存入存储,标记是不是指令消息
    is_command = message.content.startswith(ult.command_prefix)
    snipe_store[channel_id].append(
        (message.author, message.content, time.time(), is_command)
    )
    # 超过最大存储量就删掉最早的
    if len(snipe_store[channel_id]) > MAX_SNIPE_PER_CHANNEL:
        snipe_store[channel_id].pop(0)

@ult.event
async def on_bulk_message_delete(messages):
    # 批量删除事件触发时,逐个处理被删消息
    for message in messages:
        await on_message_delete(message)

@ult.command()
async def snipe(ctx, index: int = 0):
    channel = ctx.channel
    channel_id = channel.id
    # 先清过期消息
    clean_expired(channel_id)
    # 过滤掉指令消息,取有效用户消息
    valid_messages = [item for item in snipe_store[channel_id] if not item[3]]
    if not valid_messages:
        await ctx.send(f"There are no deleted messages in #{channel.name}")
        return
    # 支持指定索引取更早的消息,默认0是最新一条
    if index < 0 or index >= len(valid_messages):
        await ctx.send(f"仅存{len(valid_messages)}条可 snipe 的消息,索引范围为0到{len(valid_messages)-1}")
        return
    author, content, _, _ = valid_messages[-(index+1)]
    snipeEmbed = discord.Embed(title=f"Last deleted message in #{channel.name}", description = content)
    snipeEmbed.set_footer(text=f"Deleted by {author}")
    await ctx.send(embed = snipeEmbed)

核心修改说明

  • 新增on_bulk_message_delete事件监听,处理clear指令批量删除的消息
  • 存储结构改为每个频道存多条被删消息,不会因为最后删除的指令消息覆盖普通用户消息
  • 增加过期消息自动清理逻辑,替代原有不稳定的sleep协程方案
  • 新增过滤规则自动排除指令类消息,snipe默认返回最新的普通用户被删消息,也支持传入索引参数获取更早的被删消息,比如$snipe 1返回倒数第二条被删的普通消息

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 01:57:02