为啥我的不和谐机器人不发送每日消息

Posted

技术标签:

【中文标题】为啥我的不和谐机器人不发送每日消息【英文标题】:Why is my discord bot not sending a daily message为什么我的不和谐机器人不发送每日消息 【发布时间】:2021-11-30 15:08:06 【问题描述】:

显然缺少一些代码,但这里是所有需要帮助的代码。

import os
import discord
import requests
import json
import asyncio

channel_id = 791884298810163200

def get_quote():
    response = requests.get("https://zenquotes.io/api/random")
    json_data = json.loads(response.text)
    quote = json_data[0]["q"] + " -" + json_data[0]["a"]
    return quote

async def sendQuote():
    channel = client.get_channel(channel_id)
    await channel.send(get_quote())


async def background_task():
    #if not 8am, wait until 8am (ignoring the seconds place, doesn't have to be exactly 8am)
    await sendQuote() #fix this
    await asyncio.sleep(5) #change this to the number of seconds in a twenty four hour period when done testing
    await background_task()

if __name__ == "__main__":
    client.loop.create_task(background_task())
    keep_alive()
    client.run(my_secret)

我还没有添加等到早上 8 点部分,因为它在测试中不需要。如果我移动channel = client.get_channel(channel_id) await channel.send(get_quote()) 进入 on_ready() 它会打印报价,所以我真的不确定 sendQuote() 出了什么问题

我的错误是:

Task exception was never retrieved future: <Task finished name='Task-1' coro=<background_task() done, defined at main.py:31> exception=AttributeError("'NoneType' object has no attribute 'send'")> Traceback (most recent call last): File "main.py", line 33, in background_task await sendQuote()
#fix this File "main.py", line 28, in sendQuote await channel.send(get_quote()) AttributeError: 'NoneType' object has no attribute 'send

【问题讨论】:

嗨@joseph-spielman,请edit您的问题并将上面的评论移到问题中。 你不应该在你的'sendQuote()' 中有这个等待调用'await bot.wait_until_ready()'。所以它可以等到机器人准备好,即执行'on_ready()'函数。 不是 async/await 的大用户,但我有一种强烈的感觉,该代码有问题......首先,你为什么在同一个 background_task() 方法中调用 background_task() ?你已经有效地使它递归了,为了什么?!其次,如果您需要每天运行一次代码 - 上帝保佑,不要在您的程序中设置计时器,只需使用系统任务调度程序,它在 Windows 和 Linux 上都可用,它将使您的代码简单明了.最后,如果您仍然认为您需要这种设计,我建议您在第 28 行之前从 pprint(channel) 开始进行一些调试打印 如果您希望每隔一段时间发送一次内容,只需在 async 函数内运行 while True 循环,在循环内放入 await asyncio.sleep(x),然后执行 asyncio.get_event_loop().run_until_complete(asyncio.gather(client.start(my_secret), daily_loop(), ...))asyncio.gather 基本上需要一堆异步函数调用(not await 它们)然后使它们并发,因此您可以使用 loop.run_until_complete 一起运行它们。 【参考方案1】:

我执行了你的代码,唯一的问题是没有等待我在comment above 中提到的client.wait_until_ready()。在on_ready() 作为客户端/机器人仍​​在设置之前,channel = client.get_channel(channel_id) 返回None,从而导致以下Attribute Error

AttributeError: 'NoneType' object has no attribute 'send'

请在discordpy official documentation 中找到有关wait_until_readyon_ready API 调用的完整信息。

以下是对我有用的经过轻微修改的完整代码,

import os
import discord
import requests
import json
import asyncio

channel_id = 000000000000000000
client = discord.Client()

def get_quote():
    response = requests.get("https://zenquotes.io/api/random")
    json_data = json.loads(response.text)
    quote = json_data[0]["q"] + " -" + json_data[0]["a"]
    return quote

async def sendQuote():
    # wait till the client has executed on_ready().
    await client.wait_until_ready()
    channel = client.get_channel(channel_id)
    await channel.send(get_quote())


async def background_task():
    #if not 8am, wait until 8am (ignoring the seconds place, doesn't have to be exactly 8am)
    await sendQuote() #fix this
    await asyncio.sleep(5) #change this to the number of seconds in a twenty four hour period when done testing
    await background_task()

if __name__ == "__main__":
    client.loop.create_task(background_task())
    #keep_alive() - unknown function code, so commented it in here.
    client.run(my_secret)

【讨论】:

谢谢,我找到了另一种方法,但我将改回这种方法,因为它的代码比我最终让它工作的代码少得多。【参考方案2】:

你在做什么不是一个好主意。 您正在对background_task() 进行递归调用,这将工作一段时间,但您迟早会遇到递归错误,您的代码将失败。

查看 discord.py 中的 Tasks 扩展,它提供了重复执行任务的功能,完全符合您的要求 :)

https://discordpy.readthedocs.io/en/latest/ext/tasks/index.html

【讨论】:

以上是关于为啥我的不和谐机器人不发送每日消息的主要内容,如果未能解决你的问题,请参考以下文章

如何删除我的不和谐机器人在特定频道中发送的先前消息?

让您的不和谐机器人保存您发送的消息

如何让我的不和谐机器人回复“跟进”消息

如何让我的不和谐机器人响应没有前缀的消息

我的不和谐机器人循环了很多消息(discord.js)

如何让我的不和谐机器人在聊天中显示,例如“机器人正在打字”