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

