Discord Bot中client.loop.create_task调用报错的技术问询
问题:Discord Bot调用
client.loop.create_task触发AttributeError 搭建Discord Bot时,编写了update_stats函数用于统计服务器消息数、新成员数并写入stats.txt,但调用client.loop.create_task(update_stats())时出现以下错误:
File "C:\Users\.vscode\repo\discord bot\bot2", line 84, in <module> client.loop.create_task(update_stats()) ^^^^^^^^^^^^^^^^^^^^^^^ 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
原因
discord.py v2.0+版本移除了在非异步上下文直接访问client.loop的支持,必须通过异步初始化钩子或异步主函数来创建后台任务。
解决方案
方法1:使用setup_hook异步钩子
在client实例化后,添加setup_hook函数注册后台任务:
client = discord.Client(intents=intents) async def setup_hook(): client.loop.create_task(update_stats()) client.setup_hook = setup_hook
方法2:使用异步主函数
将Bot启动逻辑放入异步主函数,通过asyncio.run执行:
async def main(): async with client: client.loop.create_task(update_stats()) await client.start(TOKEN) asyncio.run(main())
(注意:此方式需删除原代码末尾的client.run(TOKEN)和client.loop.create_task(update_stats()))
代码其他问题修正
除上述报错外,代码还有几处逻辑/语法错误需要修正:
on_member_join模块:member.server改为member.guild(discord.py v1.5+已弃用server属性)joined += joined改为joined += 1(原逻辑会让数值翻倍,统计错误)str(channel) == ['general', 'welcome']改为channel.name in ['general', 'welcome'](原逻辑是字符串与列表比较,永远为False)- 移除过时的
client.send_message,改为await channel.send(...)
ID类型问题:
client.get_guild("client id")改为client.get_guild(123456789)(服务器ID必须是整数,不能是字符串)await client.fetch_channel("")填入正确的整数频道ID,比如await client.fetch_channel(987654321)
权限补充:
- 开启成员意图:
intents.members = True,否则无法触发on_member_join事件
- 开启成员意图:
修正后的完整代码示例
import os import time import asyncio import discord from discord import app_commands from discord.ui import button, view from discord.ext import commands, tasks # 替换为实际的Token和服务器信息 TOKEN = 'your_bot_token' GUILD = "your_guild_name" CHANNEL_ID = 123456789 # 欢迎频道ID GUILD_ID = 987654321 # 服务器ID messages = joined = 0 intents = discord.Intents.default() intents.message_content = True intents.members = True # 开启成员意图 client = discord.Client(intents=intents) async def update_stats(): await client.wait_until_ready() global messages, joined while not client.is_closed(): try: with open("stats.txt", "a") as f: f.write(f"Time : {int(time.time())}, Messages : {messages}, Members Joined : {joined}\n") messages = 0 joined = 0 await asyncio.sleep(5) except Exception as e: print(e) await asyncio.sleep(5) # 注册后台任务 async def setup_hook(): client.loop.create_task(update_stats()) client.setup_hook = setup_hook @tasks.loop(seconds=5) async def auto_send(channel : discord.TextChannel): await channel.send("Welcome") @client.event async def on_ready(): if not auto_send.is_running(): channel = await client.fetch_channel(CHANNEL_ID) auto_send.start(channel) guild = discord.utils.get(client.guilds, name=GUILD) if guild: print( f'{client.user} 已成功连接到服务器:\n' f'{guild.name}(id: {guild.id})' ) await client.change_presence( activity=discord.Activity(name='anything', type=discord.ActivityType.playing) ) @client.event async def on_member_join(member): global joined joined += 1 for channel in member.guild.channels: if channel.name in ['general', 'welcome']: await channel.send(f"Welcome to the server! {member.mention}") @client.event async def on_message(message): global messages messages += 1 guild = client.get_guild(GUILD_ID) channels = ["welcome", "mods" ,"general", "bot-commands", "admins"] valid_users = ["your_username"] # 替换为实际用户名 if str(message.channel) in channels and str(message.author) in valid_users : print(message.content) if message.content.find("!hello") != -1: await message.channel.send("Hi") elif message.content == '!users' and guild: await message.channel.send(f"成员数量 : {guild.member_count}") else: print(f"用户 : {message.author} 尝试在 #{message.channel} 频道执行命令 {message.content}!") client.run(TOKEN)
内容的提问来源于stack exchange,提问作者yewzzy_dev
相关产品推荐
相关产品推荐

