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

将命令触发的循环发消息Bot改为启动自动运行的问题求助

问题:将Discord Bot从命令触发改为启动自动运行

原有命令触发实现

之前的Bot通过命令触发(比如输入+start 192839345345812312 10),就能按指定间隔向指定频道循环发送消息,代码如下:

@bot.command()
async def start(ctx, channelid, time):
    channel_id = int(channelid)
    channel = bot.get_channel(channel_id)
    sleeptime = int(time)

    loopcheck = 0
    while 1:
        if loopcheck == len(SElist):
            loopcheck = int(0)
        loopcheck = loopcheck + 1
        await channel.send(random.choice(SElist))
        print(f'Sent message to #{channel.name}')
        await asyncio.sleep(sleeptime)

当前尝试的自动启动代码(无法运行)

现在想让Bot启动时自动执行发送逻辑,从channels.json读取频道ID和间隔时间,为每个条目启动循环任务,但编写的代码无法运行:

@bot.event
async def on_ready():

    with open("channels.json", "r") as read_file:
        decodedArray = json.load(read_file)

        finalNumpyArrayOne = numpy.asarray(decodedArray["channels"])
        for x in finalNumpyArrayOne:
            print(x[0])
            async def start(ctx, channelid, time):
                channel_id = int(x[0])
                channel = bot.get_channel(channel_id)
                sleeptime = int(x[1])
                await channel.send(random.choice(SElist))
                await asyncio.sleep(sleeptime)

问题分析与修复方案

存在的问题

  1. 循环内定义了异步函数但从未调用,任务根本不会启动
  2. 没必要用numpy.asarray处理JSON数据,直接遍历原生列表即可
  3. 循环变量x存在作用域陷阱,所有定义的函数会共享同一个x引用,最终全部使用最后一个频道的配置
  4. 丢失了原代码的无限循环逻辑,只会发送一次消息

修复后的代码

import asyncio
import json
import random
# 请确保已导入你的bot实例和SElist变量

@bot.event
async def on_ready():
    print("Bot已上线,启动自动发送任务...")
    
    # 读取配置文件,无需numpy处理
    with open("channels.json", "r") as read_file:
        config = json.load(read_file)
        channels_config = config.get("channels", [])
    
    # 为每个频道启动独立的异步发送任务
    for channel_info in channels_config:
        channel_id = int(channel_info[0])
        sleeptime = int(channel_info[1])
        asyncio.create_task(auto_send_task(channel_id, sleeptime))

async def auto_send_task(channel_id, sleeptime):
    # 等待Bot缓存频道信息,避免刚上线时无法获取频道
    channel = bot.get_channel(channel_id)
    while channel is None:
        await asyncio.sleep(1)
        channel = bot.get_channel(channel_id)
    
    loopcheck = 0
    while True:
        # 保留原有的循环计数器逻辑(不需要可删除)
        if loopcheck == len(SElist):
            loopcheck = 0
        loopcheck += 1
        
        try:
            await channel.send(random.choice(SElist))
            print(f'已发送消息到 #{channel.name}')
        except Exception as e:
            print(f'频道 {channel_id} 发送失败: {str(e)}')
        
        await asyncio.sleep(sleeptime)

补充说明

  • channels.json的标准格式示例:
    {
        "channels": [
            ["192839345345812312", 10],
            ["987654321098765432", 30]
        ]
    }
    
  • 使用asyncio.create_task让多个发送任务并发运行,互不阻塞
  • 增加频道对象重试逻辑,避免Bot刚上线时缓存未加载完成的报错
  • 添加异常捕获,防止单个频道发送失败导致整个Bot停止运行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 17:20:49