PAYATHON 2026

如何使用 discord.py 跟踪入会申请并提醒审核人员?

数据小陈

可以通过原始 Gateway 事件尝试实现提醒

如果使用 Discord 自带的 Apply to Join 入会申请,而 discord.py 尚未封装对应的高级事件,可以尝试监听原始 Gateway 消息,向工作人员频道发送 @ 提醒。

查阅时,discord.py 的入会申请支持 PR #10497 仍处于 Open 状态,稳定版 API 文档也没有对应的 join_request 接口。因此,不能直接把开发中 PR 的事件名称当作已发布 API 使用,但这也不意味着机器人完全无法收到申请事件。

为什么不能用成员加入事件代替

你的目标是在申请等待审核时通知工作人员。Discord 的 Apply to Join 要求申请获批后才能加入服务器,等待中的申请人无法查看服务器内容。这个阶段与普通成员加入不同。Discord 入会申请说明

几个容易混淆的事件和属性分别用于不同的情况:

  • on_member_join:成员加入服务器,不能直接代表提交了入会申请。
  • Member.pending:成员是否还在等待完成 Membership Screening。
  • on_member_update:可用于观察 pending 等成员属性变化,不能用来读取入会申请表。

例如,before.pending and not after.pending 表示成员完成了规则筛选,但不能据此判断有新的人工审核申请。discord.py 成员事件与属性文档

接入申请事件前需要确认什么

Discord 的入会申请文档草案列出了以下 Gateway 事件:

  • GUILD_JOIN_REQUEST_CREATE
  • GUILD_JOIN_REQUEST_UPDATE
  • GUILD_JOIN_REQUEST_DELETE

草案要求机器人具备 KICK_MEMBERS 权限,服务器也需要启用相应的申请审核功能;接收创建事件还涉及 GUILD_MODERATION intent。这份文档的 PR #8531 查阅时尚未合并,接入时应再次确认 PR 状态和实际事件结构。

准备步骤如下:

  1. 确认服务器使用的是 Apply to Join。
  2. 为机器人配置所需的 KICK_MEMBERS 权限,并在代码中开启 intents.moderation。
  3. 为通知频道配置查看频道和发送消息的权限。
  4. 确保工作人员角色允许被提及,或者机器人具有相应的提及权限。
  5. 用测试申请确认实际收到的事件名称、申请 ID 和状态字段。

不要把 CREATE 一律视为“已提交待审核”。文档草案区分了 STARTED 和 SUBMITTED 等状态,提醒逻辑应筛选 SUBMITTED,并留意状态通过更新事件发生变化的情况。

使用 discord.py 监听原始事件

on_socket_raw_receive 可以收到尚未由库解析的 WebSocket 消息,但必须在创建客户端时开启 enable_debug_events=True。discord.py 原始消息事件文档

下面的示例从事件数据的 request 对象读取申请信息。使用前,需要将这一结构与你实际收到的载荷核对。示例使用提供 Intents.moderation 的 discord.py 2.x,代码尚未在目标服务器实测。

import json
import logging
import os

import discord

GUILD_ID = 123456789012345678
STAFF_CHANNEL_ID = 234567890123456789
STAFF_ROLE_ID = 345678901234567890

intents = discord.Intents.none()
intents.guilds = True
intents.moderation = True

client = discord.Client(
    intents=intents,
    enable_debug_events=True,
)

# 演示用去重集合;重启后会清空。
notified = set()


@client.event
async def on_socket_raw_receive(msg):
    try:
        payload = json.loads(msg)
    except (json.JSONDecodeError, UnicodeDecodeError, TypeError):
        return

    if payload.get('op') != 0:
        return

    if payload.get('t') not in {
        'GUILD_JOIN_REQUEST_CREATE',
        'GUILD_JOIN_REQUEST_UPDATE',
    }:
        return

    data = payload.get('d') or {}
    if str(data.get('guild_id')) != str(GUILD_ID):
        return

    request = data.get('request')
    if not isinstance(request, dict):
        logging.warning('申请事件结构不符合预期,请核对载荷字段')
        return

    if request.get('status') != 'SUBMITTED':
        return

    request_id = request.get('id')
    if request_id is None:
        logging.warning('申请事件缺少预期的申请 ID 字段')
        return

    key = (GUILD_ID, str(request_id))
    if key in notified:
        return

    try:
        channel = client.get_channel(STAFF_CHANNEL_ID)
        if channel is None:
            channel = await client.fetch_channel(STAFF_CHANNEL_ID)

        if not isinstance(channel, discord.TextChannel):
            logging.error('通知频道必须是服务器文字频道')
            return
        if channel.guild.id != GUILD_ID:
            logging.error('通知频道不属于目标服务器')
            return

        await channel.send(
            f'<@&{STAFF_ROLE_ID}> 有新的入会申请待审核,请查看申请列表。',
            allowed_mentions=discord.AllowedMentions(
                everyone=False,
                users=False,
                roles=[discord.Object(id=STAFF_ROLE_ID)],
                replied_user=False,
            ),
        )
    except discord.HTTPException:
        logging.exception('发送入会申请提醒失败')
        return

    notified.add(key)


client.run(os.environ['DISCORD_BOT_TOKEN'])

替换三个 ID,并通过环境变量提供机器人 Token。已有机器人项目可以把监听逻辑整合到现有客户端中,创建客户端时保留 enable_debug_events=True。

如果收不到事件,监听原始消息也无法补出申请数据。先检查申请功能、权限和 intent,再确认 Discord 是否向该机器人下发相应事件。排查载荷时只记录必要字段,避免将申请回答完整写入普通日志。

怎样减少重复提醒和漏报

示例只演示在线通知,长期运行还需要补充两点:

  • 持久化去重和重试:用服务器 ID、申请 ID 保存通知状态,并在并发处理时避免同一申请重复发送。发送失败后需要重试;示例中的集合会随进程重启而清空。
  • 补偿离线期间的申请:实时事件无法单独保证离线期间零漏报。如果接入时可用的申请列表接口允许 Bot 查询,可以在启动后或定期核对待审核列表;调用方式、分页和权限应以当时可用的文档为准。

如果暂时无法稳定获取原生申请事件,可以先设置定时提醒,让工作人员检查 Discord 申请列表。也可以改用由你控制的外部申请表,在提交成功后调用机器人或 webhook 通知工作人员。这会改变申请入口,需要单独安排审核流程。

不要通过自动化普通用户账号来补足 Bot 接口能力;Discord 的开发文档明确限制这类 self-bot 用法。Discord 账号与 Bot 使用说明

备注:内容仅供参考。