Discord Bot无法获取频道:报错原因及修复方案咨询
Discord Bot 报错原因与修复方案
问题背景
我正在开发一款Discord Bot,需实现两大功能:
- 将服务器新消息打印至控制台
- 支持用户向服务器发送消息
实现代码如下:
import discord from asyncio import run from threading import Thread intents = discord.Intents.all() intents.members = True client = discord.Client(intents=intents) async def p(): ap = await client.fetch_channel(1234567890) return ap main_guild = run(p()) def log_msg(msge,date): with open('log.txt','a') as f: f.write(msge + '\n' + date) f.close() async def send_a_message(): while True: await main_guild.send(input('Send message: ')) @client.event async def on_message(message): base_msg = str(message.author)+': '+str(message.channel.name)+': '+str(message.content) date = str(message.created_at) if len(message.attachments) == 0: print(base_msg) log_msg(base_msg,date) return for i in range(len(message.attachments)): base_msg += '\n'+(message.attachments[i]).url log_msg(base_msg,date) t = Thread(target=lambda:run(send_a_message())) t.start() try: client.run('#######################') except discord.errors.HTTPException: from os import system system('kill 1')
运行后出现报错:
Traceback (most recent call last): File "main.py", line 13, in <module> main_guild = run(p()) File "/nix/store/hd4cc9rh83j291r5539hkf6qd8lgiikb-python3-3.10.8/lib/python3.10/asyncio/runners.py", line 44, in run return loop.run_until_complete(main) File "/nix/store/hd4cc9rh83j291r5539hkf6qd8lgiikb-python3-3.10.8/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete return future.result() File "main.py", line 10, in p ap = await client.fetch_channel(999141783709679668) File "/home/runner/RandomRepl/venv/lib/python3.10/site-packages/discord/client.py", line 1824, in fetch_channel data = await self.http.get_channel(channel_id) File "/home/runner/RandomRepl/venv/lib/python3.10/site-packages/discord/http.py", line 604, in request if not self._global_over.is_set(): AttributeError: '_MissingSentinel' object has no attribute 'is_set'
报错原因
- 客户端未初始化就调用API:
client.fetch_channel()需要在Discord客户端完成登录、建立连接后才能执行,但你在client.run()(客户端启动入口)之前就用asyncio.run(p())调用了该方法,此时客户端内部的HTTP组件还未初始化,导致出现属性错误。 - 多线程使用不当:用Thread启动异步任务的方式破坏了asyncio事件循环的线程安全性,Discord客户端的操作必须在同一个事件循环中执行。
修复方案
修复后完整代码
import discord from asyncio import create_task # 配置Intents,需确保在Discord开发者后台开启对应权限 intents = discord.Intents.all() intents.message_content = True # v2.x版本必须显式开启才能读取消息内容 client = discord.Client(intents=intents) main_channel = None # 全局变量存储目标频道 def log_msg(msge, date): with open('log.txt','a') as f: f.write(f"{msge}\n{date}\n") # 优化日志格式,增加换行分隔 async def send_a_message(): while True: if main_channel is not None: msg_input = input('Send message: ') await main_channel.send(msg_input) @client.event async def on_ready(): global main_channel # 客户端登录完成后再获取频道 main_channel = await client.fetch_channel(1234567890) # 替换为你的频道ID print(f"已登录为 {client.user},已绑定目标频道") # 用客户端事件循环启动发送任务,避免线程问题 create_task(send_a_message()) @client.event async def on_message(message): # 跳过Bot自身发送的消息,避免循环处理 if message.author == client.user: return base_msg = f"{message.author}: {message.channel.name}: {message.content}" date = str(message.created_at) if not message.attachments: print(base_msg) log_msg(base_msg, date) else: for attachment in message.attachments: base_msg += f"\n{attachment.url}" print(base_msg) log_msg(base_msg, date) try: client.run('你的Bot令牌') except discord.errors.HTTPException: from os import system system('kill 1')
关键修复点说明
- 将频道获取逻辑移至
on_ready事件:确保客户端完成登录后再调用API,避免未初始化错误。 - 移除多线程,改用
create_task:在Discord客户端的事件循环中启动发送任务,保证线程安全。 - 显式开启
message_content意图:Discord.py v2.x版本后,读取消息内容需要开启该意图,同时要在Discord开发者后台的Bot设置中开启对应的Privileged Gateway Intents。 - 增加Bot自消息过滤:防止Bot处理自己发送的消息,避免循环。
- 优化日志写入格式:增加换行让日志更易读。
内容的提问来源于stack exchange,提问作者433MEA
相关产品推荐
相关产品推荐

