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

Discord.py:统计消息唯一反应用户数 规避API速率限制

高效统计Discord消息唯一反应用户数的优化方案

要统计Discord频道中每条消息的唯一反应用户数,直接使用reaction.count属性会有问题——这个属性仅统计单个表情的反应总人数,若同一用户对同一条消息添加多个表情反应,直接求和会导致重复计数(比如用户用多个表情拼接内容的场景)。

现有代码通过集合存储用户ID实现了去重,但存在性能瓶颈:每次调用reaction.users()都会触发单独的API请求,当频道内消息和反应数量较多时,极易触发Discord的速率限制,导致请求被拦截。

现有实现代码:

import discord
from discord import app_commands
from discord.utils import get

...
@tree.command(guild=discord.Object(id=GUILD_ID))
async def get_unique_reactions(interaction: discord.Interaction):
    gallery = interaction.guild.get_channel(int(DISCORD_GALLERY_ID))
    async for message in gallery.history(after=week_ago, limit=None):
        reaction_ids = set()
        for reaction in message.reactions:
            async for user in reaction.users():
                reaction_ids.add(user.id)
        print(f"{reaction_ids}")

...

优化方案

1. 并发获取反应用户

使用asyncio.gather并行处理同一消息下的所有表情反应用户请求,减少整体等待时间,降低串行请求触发速率限制的概率。

优化后代码:

import discord
from discord import app_commands
import asyncio

...
@tree.command(guild=discord.Object(id=GUILD_ID))
async def get_unique_reactions(interaction: discord.Interaction):
    gallery = interaction.guild.get_channel(int(DISCORD_GALLERY_ID))
    async for message in gallery.history(after=week_ago, limit=None):
        reaction_ids = set()
        
        # 异步获取单个表情反应的所有用户ID
        async def fetch_reaction_users(reaction):
            user_ids = []
            async for user in reaction.users(limit=None):
                user_ids.append(user.id)
            return user_ids
        
        # 并发执行所有表情的用户获取任务
        all_user_id_groups = await asyncio.gather(
            *[fetch_reaction_users(reaction) for reaction in message.reactions]
        )
        
        # 合并所有用户ID到集合中完成去重
        for user_ids in all_user_id_groups:
            reaction_ids.update(user_ids)
        
        print(f"消息ID {message.id} 的唯一反应用户数:{len(reaction_ids)}")

2. 加入速率限制控制

若频道内反应数量极大,即使并发请求仍可能触发限制,可通过以下方式缓解:

  • 分批次获取频道历史消息,每处理一批后添加小延迟
  • 限制并发任务的数量,避免同时发起过多API请求

示例代码(分批次处理):

...
# 每次获取50条消息,处理后添加1秒延迟
async for message in gallery.history(after=week_ago, limit=50):
    # 此处放置上述并发处理逻辑
    await asyncio.sleep(1)

3. 全局缓存(针对频道总唯一用户统计)

如果需求是统计频道内所有消息的总唯一反应用户数,而非单条消息的独立统计,可维护一个全局集合来记录所有已出现的用户ID,避免重复请求同一用户的数据:

...
total_unique_users = set()

async for message in gallery.history(after=week_ago, limit=None):
    # 此处获取当前消息的所有反应用户ID
    # 直接更新全局集合
    total_unique_users.update(reaction_ids)

print(f"频道总唯一反应用户数:{len(total_unique_users)}")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 17:35:04