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

discord.py非异步上下文无法访问loop属性的问题修复求助

问题描述

运行Discord机器人代码时,机器人能正常启动,但执行/profiles命令时触发以下错误:

discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: loop attribute cannot be accessed in non-async contexts. Consider using either an asynchronous main function and passing it to asyncio.run or using asynchronous initialisation hooks such as Client.setup_hook

其他命令运行正常,多次修改(如将get_uuid设为异步函数)仍未解决。

错误原因
  1. 异步方法调用遗漏await:client.wait_for是异步方法,调用时未加await,导致在非异步上下文尝试访问事件循环属性。
  2. 异步函数调用未加await:get_uuid是异步函数,调用时未加await,触发上下文冲突。
  3. 冗余客户端实例:代码同时创建discord.Client和commands.Bot实例,造成上下文混乱。
  4. 同步请求阻塞事件循环:使用同步requests.get在异步环境中运行,虽不是直接触发当前错误,但会影响机器人性能。
修复方案

关键修改点

  • 移除冗余的discord.Client实例,统一使用commands.Bot
  • 所有异步方法/函数调用必须添加await关键字
  • 将同步HTTP请求替换为异步aiohttp请求,适配Discord.py异步环境

修复后的完整代码

import json
import os
import random
from pprint import pprint

import aiohttp
import discord
from discord.ext import commands
from dotenv import load_dotenv
from mojang import api

# 异步Get请求方法
async def get_info(call):
    async with aiohttp.ClientSession() as session:
        async with session.get(call) as r:
            return await r.json()

# 计算 bazaar 中所有收购单的总金币
def get_bazaar_buy_order_value(bazaar_data):
    sum_coins = 0
    price_increase_threshold = 2
    buy_order_values = []

    for item_name, item_data in bazaar_data.get("products", {}).items():
        item_sum_coins = 0
        for idx, buy_order in enumerate(item_data.get("buy_summary", [])):
            if idx == 0:
                item_expected_value = buy_order.get("pricePerUnit", 0)
                item_sum_coins += buy_order.get("amount", 0) * buy_order.get("pricePerUnit", 0)
            else:
                if buy_order.get("pricePerUnit", 0) < (item_expected_value * price_increase_threshold):
                    item_sum_coins += buy_order.get("amount", 0) * buy_order.get("pricePerUnit", 0)
        buy_order_values.append((item_name, item_sum_coins))
        sum_coins += item_sum_coins

    sort_bazaar_buy_orders_by_value(buy_order_values)
    return sum_coins

# 按总价值排序并打印收购单
def sort_bazaar_buy_orders_by_value(buy_order_values):
    buy_order_values.sort(key=lambda x: -x[1])
    for (item_name, item_sum_coins) in buy_order_values:
        print(f"{item_name.ljust(30, ' ')} | {round(item_sum_coins):,}")

# 获取 bazaar 数据
async def get_bazaar_data():
    return await get_info("https://api.hypixel.net/skyblock/bazaar")

# 通过UUID获取玩家拍卖信息
async def get_auctions_from_player(uuid):
    return await get_info(f"https://api.hypixel.net/skyblock/auction?key={API_KEY}&player={uuid}")

# 获取当前镇长/选举数据
async def get_election_data():
    return await get_info(f"https://api.hypixel.net/resources/skyblock/election")

# 通过UUID获取玩家档案数据
async def get_profiles_data(uuid):
    return await get_info(f"https://sky.shiiyu.moe/api/v2/profile/{uuid}")

# 通过用户名获取玩家UUID
async def get_uuid(name):
    return await get_info(f"https://sky.shiiyu.moe/api/v2/profile/{name}")

# Discord 配置
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
GUILD = os.getenv('DISCORD_GUILD')

intents = discord.Intents.all()
bot = commands.Bot(command_prefix='/', intents=intents)

# Hypixel 配置
Item = "Diamond"
API_FILE = open("API_KEY.json","r")
example_name = "4748"
example_uuid = "147ab344d3e54952b74a8b0fedee5534"
uuid_dashed = "147ab344-d3e5-4952-b74a-8b0fedee5534"
API_KEY = json.loads(API_FILE.read())["API_KEY"]
example_player_uuid = "147ab344d3e54952b74a8b0fedee5534"
auctions_player_url = f"https://api.hypixel.net/skyblock/auction?key={API_KEY}&player={example_player_uuid}"

# 命令定义
@bot.command(name='bazaar', description="获取 bazaar 中指定物品的详细数据", brief="查询 bazaar 物品数据")
async def bazaar(ctx):
    data = await get_bazaar_data()
    await ctx.send(json.dumps(data, indent=2))
    await ctx.send(API_KEY)

@bot.command(name="bazaartotal", description="显示 bazaar 中所有收购单的总金币数量", brief="查询 bazaar 总金币")
async def baztot(ctx):
    bazaar_data = await get_bazaar_data()
    await ctx.send(get_bazaar_buy_order_value(bazaar_data))

@bot.command(name="apikey", description="获取4748的API密钥,公开部署前请移除该命令", brief="获取API密钥")
async def key(ctx):
    await ctx.send(API_KEY)

@bot.command(name="profiles", description="获取指定玩家的档案列表及数据", brief="查询玩家档案")
async def prof(ctx):
    await ctx.send("请输入要查询的用户名:")
    # 使用bot实例的wait_for,添加await并修正校验条件
    message = await bot.wait_for('message', check=lambda m: m.author == ctx.author and m.channel == ctx.channel)
    username = message.content.strip()
    uuid_data = await get_uuid(username)
    pprint(uuid_data)
    await ctx.send(json.dumps(uuid_data, indent=2))

bot.run(TOKEN)
额外说明
  • 所有原同步HTTP请求改为异步,避免阻塞机器人事件循环
  • wait_for增加了频道校验,确保只接收当前频道的用户输入,避免跨频道干扰
  • 发送JSON数据时使用json.dumps格式化,提升消息可读性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 18:10:30