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

Discord Bot命令读取JSON文件等级数据的问题排查

问题说明

你已知晓JSON不适合作为生产数据库,本次仅为测试JSON格式的应用可行性,不会长期使用JSON存储数据。本次开发目标是适配多服务器的Discord等级机器人,需要实现用户查询自身等级的命令,用户ID、等级、累计经验值存储在本地users.json文件中,当前自行编写的代码无法正常运行,以下是具体问题排查、修复方案和通用开发优化建议。

代码问题排查

你的代码存在以下直接导致运行失败的问题:

  • 命令参数定义错误:!level命令的函数除了框架自动传入的上下文ctx外,额外定义了users/user/channel三个参数,Discord命令框架会默认将用户输入的命令内容按顺序匹配这些参数,用户仅输入!level时会直接报参数缺失错误。实际上ctx.author就是调用命令的用户,ctx.channel就是当前命令所在频道,不需要额外作为参数声明。
  • 缺少命令处理调用:自定义on_message事件监听后,没有添加await client.process_commands(message),会导致所有前缀命令被事件拦截,根本不会触发命令逻辑,这是!level无响应的核心原因之一。
  • 重复调用client.run():代码末尾写了两次client.run(),第一次调用后程序就会进入阻塞状态,第二次代码永远不会执行,两种读取环境变量的逻辑重复,保留一个即可。
  • 缩进错误:on_message事件中更新用户发言冷却时间的member_messages[message.author.id] = current_time被错误缩进在json.dump的文件写入代码块内,逻辑位置错误,会导致冷却时间更新异常。
  • 缺少机器人消息过滤:on_message事件没有判断消息发送者是否为机器人,会导致机器人自己发消息时给自己涨经验,逻辑错误。
  • 缺少意图配置:新版discord.py默认关闭特权意图,没有配置intents的情况下,on_member_join、消息内容相关事件根本无法被接收,机器人无法正常工作。
  • 缺少异常和边界判断:
    1. 第一次运行时如果users.json不存在,直接读取会报文件不存在错误
    2. 查询等级时如果用户没有在JSON中存储数据,level_information为None,直接调用.get('level')会抛出属性错误导致命令崩溃
    3. 读写文件没有指定utf-8编码,Windows环境下容易出现乱码或读取失败
  • 无用导入和笔误:导入了random模块但全程未使用;add_experience函数的形参exprience拼写错误(正确为experience),虽不影响运行但属于代码瑕疵。
修复后完整代码
from discord.ext import commands
from time import time
import json
import discord
import os

# 配置意图,需要提前在Discord开发者后台开启对应特权意图
intents = discord.Intents.default()
intents.members = True
intents.message_content = True
client = commands.Bot(command_prefix="!", intents=intents)

# 启动时初始化/加载用户数据到内存,避免频繁读写文件
if not os.path.exists("users.json"):
    with open("users.json", "w", encoding="utf-8") as f:
        json.dump({}, f)
with open("users.json", "r", encoding="utf-8") as f:
    users_data = json.load(f)

# 发言冷却记录
member_messages = {}

async def update_data(user):
    """更新用户数据,不存在则初始化"""
    user_id = str(user.id)
    if user_id not in users_data:
        users_data[user_id] = {
            "experience": 0,
            "level": 1
        }

async def add_experience(user, exp):
    """给用户增加经验"""
    user_id = str(user.id)
    users_data[user_id]["experience"] += exp

async def level_up(user, channel):
    """检查升级并发送通知"""
    user_id = str(user.id)
    experience = users_data[user_id]["experience"]
    level_start = users_data[user_id]["level"]
    level_end = int(experience ** (1/4))

    if level_start < level_end:
        await channel.send(f"{user.mention} Has Leveled Up! They Have Leveled Up To Level {level_end}!")
        users_data[user_id]["level"] = level_end
        # 数据变更后写回文件
        with open("users.json", "w", encoding="utf-8") as f:
            json.dump(users_data, f, indent=2)

@client.listen()
async def on_ready():
    print("Bot Ready.")
    print(f"Logged In As: {client.user}")

@client.listen()
async def on_member_join(member):
    await update_data(member)
    with open("users.json", "w", encoding="utf-8") as f:
        json.dump(users_data, f, indent=2)

@client.listen()
async def on_message(message):
    # 过滤机器人自己发的消息
    if message.author.bot:
        return
    # 必须加这行,否则前缀命令无法正常触发
    await client.process_commands(message)

    global member_messages
    user_id = message.author.id
    if user_id not in member_messages:
        member_messages[user_id] = 0

    current_time = time()
    # 2秒发言冷却,防止刷经验
    cooldown_time = current_time - 2
    if member_messages[user_id] <= cooldown_time:
        await update_data(message.author)
        await add_experience(message.author, 5)
        await level_up(message.author, message.channel)
        member_messages[user_id] = current_time

@client.command(name="level")
async def get_level(ctx):
    """查询自身等级命令"""
    user_id = str(ctx.author.id)
    # 确保用户数据存在
    await update_data(ctx.author)
    level = users_data[user_id]["level"]
    exp = users_data[user_id]["experience"]
    await ctx.send(f"{ctx.author.mention} Is Level {level}, Current EXP: {exp}.")

# 按自己的环境变量配置选一种即可
client.run(os.getenv("Token"))
Discord机器人通用开发优化建议
  • 提前配置特权意图:在Discord开发者后台对应机器人的「Bot」页面,下拉找到「Privileged Gateway Intents」板块,开启Server Members Intent和Message Content Intent,否则成员事件、消息读取事件都无法正常接收,代码里的intents配置要和后台开启的选项对应。
  • 减少高频文件IO:不要每次消息触发、每次命令调用都开关读写JSON文件,启动时把数据加载到内存,数据变更时再写回文件,也可以加定时自动存盘逻辑,避免程序意外崩溃丢失数据,同时降低磁盘占用。
  • 多服务器数据隔离:如果需要每个服务器的等级独立不互通,存储用户数据的key不要只用用户ID,要改成{服务器ID}_{用户ID}的格式,避免跨服数据互通不符合需求。
  • 添加全局错误处理:给命令、事件都加异常捕获,比如JSON文件损坏、权限不足无法发送消息的情况,不要让机器人直接崩溃,输出错误日志方便排查问题。
  • 冷却逻辑优化:当前用内存字典存发言冷却,机器人重启后冷却会重置,如果对冷却要求严格可以把冷却时间也持久化存储;命令类的冷却可以直接用discord.py自带的@commands.cooldown()装饰器实现,不用自己手写逻辑。
  • 调整等级公式:当前用经验开四次方的升级公式,后期升级需要的经验会指数级上涨,可以根据需求调整成线性升级(比如每级固定需要100经验)或者自定义成长曲线,用户体验更好。
  • 增加权限校验:后续添加管理类命令(比如给用户加经验、重置等级)的时候,一定要加权限判断,只允许服务器管理员使用这类命令,避免普通用户恶意修改数据。

内容的提问来源于stack exchange,提问作者Broski Man

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