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
相关产品推荐
相关产品推荐

