You need to enable JavaScript to run this app. Python Discord机器人运行报错 命令无法更新对应服务器JSON数据库
优惠活动
大模型
产品
解决方案
定价
更多

Python Discord机器人运行报错 命令无法更新对应服务器JSON数据库

问题定位与修复指南

核心问题排查

  • 专属JSON文件路径生成逻辑完全错误:现有代码拼接文件路径用的是str(bot.guilds) + ".json",转义后会生成包含机器人所有已加入服务器列表的字符串,对应路径完全无效,系统无法找到可读写的文件,直接触发IO类报错。正确的路径生成逻辑需要从命令触发的上下文ctx.guild.id获取当前服务器的唯一ID,每个服务器对应一个以自身ID命名的独立JSON文件。
  • Discord.py 版本API适配错误:现有代码使用的是已停止维护的discord.py 0.x版本接口,当前主流的1.x/2.x版本中,不存在client.send_message、ctx.quote、ctx.timestamp、ctx.content这些废弃属性,运行时会直接报属性不存在的错误。
  • 发送消息统一用上下文自带的ctx.send()方法,替代原有的client.send_message(message.channel, 内容)写法
  • 命令输入内容直接通过Discord.py内置的参数解析功能捕获,不需要手动从消息字符串里截取、替换命令前缀
  • 操作人信息、消息时间戳分别对应上下文的ctx.author、ctx.message.created_at属性,不需要从旧版上下文中提取
  • 新增服务器的文件初始化兜底缺失:新接入的服务器对应的JSON存储文件不存在时,直接以只读模式打开会直接报错,需要增加文件存在性判断,不存在时自动初始化符合结构要求的空JSON文件再读写。
  • 随机数生成逻辑有边界漏洞:randomquote命令里的随机数范围写为random.randint(1, len(parsed_json["quotes"]) -1),当服务器没有任何语录时,会生成从1到-1的无效范围,直接触发数值范围错误,需要增加空数据判断分支。
  • 手动命令前缀匹配可靠性差:现有代码通过字符串替换手动识别命令、截取参数,很容易因为用户输入带多余空格、自定义前缀不匹配导致参数提取错误,直接使用Discord.py内置的命令参数解析可以完全规避这类问题。

修复后的可运行参考代码

import json
import random
from pathlib import Path
from discord.ext import commands

# 初始化机器人,设置命令触发前缀
bot = commands.Bot(command_prefix="!")

# 工具函数:根据服务器ID获取专属数据文件路径
def get_guild_db_path(guild_id: int) -> Path:
    return Path(f"./guild_data/{guild_id}.json")

# 工具函数:读取对应服务器的数据库,文件不存在时自动初始化空结构
def read_guild_db(guild_id: int) -> dict:
    db_path = get_guild_db_path(guild_id)
    db_path.parent.mkdir(exist_ok=True)
    if not db_path.exists():
        default_data = {"quotes": {}}
        with open(db_path, "w", encoding="utf-8") as f:
            json.dump(default_data, f, ensure_ascii=False, indent=2)
        return default_data
    with open(db_path, "r", encoding="utf-8") as f:
        return json.load(f)

# 工具函数:将修改后的数据库内容写回对应服务器的JSON文件
def write_guild_db(guild_id: int, data: dict):
    db_path = get_guild_db_path(guild_id)
    with open(db_path, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

@bot.command()
async def addquote(ctx, *, quote_content: str):
    db = read_guild_db(ctx.guild.id)
    next_quote_id = str(len(db["quotes"]) + 1)
    db["quotes"][next_quote_id] = {
        "content": quote_content,
        "addedby": str(ctx.author),
        "add_date": str(ctx.message.created_at.date())
    }
    write_guild_db(ctx.guild.id, db)
    await ctx.send(f"已添加编号为 {next_quote_id} 的语录")

@bot.command()
async def addquotename(ctx, name: str, *, quote_content: str):
    db = read_guild_db(ctx.guild.id)
    next_quote_id = str(len(db["quotes"]) + 1)
    db["quotes"][next_quote_id] = {
        "name": name,
        "content": quote_content,
        "addedby": str(ctx.author),
        "add_date": str(ctx.message.created_at.date())
    }
    write_guild_db(ctx.guild.id, db)
    await ctx.send(f"已添加名为 {name} 的语录")

@bot.command()
async def randomquote(ctx):
    db = read_guild_db(ctx.guild.id)
    if not db["quotes"]:
        await ctx.send("当前服务器暂未存储任何语录")
        return
    quote_num = random.choice(list(db["quotes"].keys()))
    quote = db["quotes"][quote_num]
    await ctx.send(f"随机语录 {quote_num}:{quote['content']}")

@bot.command()
async def quoteaddedby(ctx, quote_num: int):
    db = read_guild_db(ctx.guild.id)
    quote_id = str(quote_num)
    if quote_id not in db["quotes"]:
        await ctx.send(f"不存在编号为 {quote_num} 的语录,当前服务器共有 {len(db['quotes'])} 条语录")
        return
    author = db["quotes"][quote_id]["addedby"]
    await ctx.send(f"编号为 {quote_num} 的语录添加者为:{author}")

# 运行时替换为自己的机器人Token即可启动
# bot.run("你的机器人API Token")

注意:启动前需要提前在机器人运行的开发者后台开启对应的Message Content Intent权限,否则无法正常响应命令。

内容的提问来源于stack exchange,提问作者André Peixinho

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.31 11:24:06