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

discord.py如何正确在json存储用户ID、词频计数及实现查询命令

问题根因
  • 多词汇统计失效:一是存在语法错误,判断键是否存在的写法if authorid {'bye'} in log_data不符合Python语法规则,无法正常执行判断;二是用户记录已存在时,匹配到新词汇会直接执行log_data[str(message.author.id)] = {}清空该用户原有统计数据,最终只会保留最后一次匹配到的单类词汇计数。
  • 查询命令失效:一是存储时用户ID被转为字符串类型,查询时直接用整数类型的ctx.author.id作为键取值会触发KeyError;二是存在基础语法错误,json.dump行多了一个右括号、ctx.reply行末尾多了多余的单引号,代码无法正常运行;三是没有做无数据场景的兜底判断,用户没有对应分类的统计数据时直接取嵌套键会直接报错。另外原逻辑每次匹配到词汇都会重复读写文件、重复定义变量,冗余度很高。
修正后的可运行代码

优化后把词汇分类做成可配置项,后续新增统计维度不需要修改核心逻辑,统一了数据类型、补全错误兜底、减少不必要的文件读写:

import json
import discord
from discord.ext import commands

# 替换为你自己的bot配置,记得在开发者后台开启Message Content Intent权限
bot = commands.Bot(command_prefix='!', intents=discord.Intents.all())

def load_stats():
    try:
        with open('stats.json', 'r', encoding='utf-8') as f:
            return json.load(f)
    # 文件不存在或为空时返回空字典,避免启动报错
    except (FileNotFoundError, json.JSONDecodeError):
        return {}

def save_stats(stats):
    with open('stats.json', 'w', encoding='utf-8') as f:
        json.dump(stats, f, indent=4, ensure_ascii=False)

# 词汇分类配置,后续加新统计维度直接往这里追加即可
WORD_CATEGORIES = {
    "bye": ["bye", "cya", "bb", "gn8", "cya later"],
    "hey": ["hello", "hey", "hi", "greetings", "good morning", "good afternoon"]
}

@bot.listen()
async def on_message(message):
    # 跳过机器人自身消息,避免循环统计
    if message.author.bot:
        return
    msg_content = message.content.lower()
    authorid = str(message.author.id)
    stats = load_stats()
    need_save = False

    # 遍历所有分类匹配,不用重复写判断逻辑
    for category, words in WORD_CATEGORIES.items():
        if any(word in msg_content for word in words):
            await loging.meslog_green(bot, message, category)
            # 用户不存在则初始化空记录
            if authorid not in stats:
                stats[authorid] = {}
            # 分类不存在则初始化计数为0
            if category not in stats[authorid]:
                stats[authorid][category] = 0
            stats[authorid][category] += 1
            need_save = True
    
    # 所有匹配完成后仅存一次文件,降低IO开销
    if need_save:
        save_stats(stats)

@bot.command(name='mystats')
async def mystats(ctx):
    authorid = str(ctx.author.id)
    stats = load_stats()
    # 无统计数据时兜底
    if authorid not in stats or not stats[authorid]:
        await ctx.reply("你还没有产生任何词频统计记录", delete_after=10.0)
        await loging.comlog_green(bot, ctx, 'mystats')
        return
    # 拼接所有分类的统计结果
    stat_list = [f"{cate}:{count}次" for cate, count in stats[authorid].items()]
    reply_content = "你的词频统计结果:\n" + "\n".join(stat_list)
    await ctx.reply(reply_content, delete_after=10.0)
    await loging.comlog_green(bot, ctx, 'mystats')

# 保留原单类查询命令
@bot.command(name='hey')
async def hey(ctx):
    authorid = str(ctx.author.id)
    stats = load_stats()
    hey_count = stats.get(authorid, {}).get("hey", 0)
    await ctx.reply(f'你一共说了{hey_count}次hey类问候语', delete_after=10.0)
    await loging.comlog_green(bot, ctx, 'hey')

# 替换为你自己的bot token
# bot.run("你的BOT_TOKEN")
修正后存储结构示例

该结构天然支持多分类统计,后续新增词汇分类不需要调整存储格式:

{
    "448827301235084672": {
        "hey": 2,
        "bye": 1
    }
}
注意事项
  • 必须去Discord开发者后台为机器人开启Message Content Intent权限,否则on_message事件无法获取消息内容
  • 所有涉及用户ID存取的位置统一转为字符串类型,避免整数/字符串类型不匹配触发KeyError
  • 新增统计维度时,只需要往WORD_CATEGORIES字典中添加对应的分类名和关键词列表即可,不需要修改消息监听、存储、查询的核心逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 21:00:56