Using tweepy with discord.py to post tweets to a specific channel
因此,我正在尝试通过结合使用教程,文档和在线示例来自学Python,以构建一个Discord机器人,该机器人实现一个或多个现有bot的某些功能。这些功能之一是将来自一组特定Twitter帐户的(新)推文发布到我的Discord服务器上的特定频道。我找到了一些拼凑在一起的代码,可以从Twitter流中读取这些代码,并且在这里和那里"调整"了一些东西,以尝试实现此目的。
但是,我一直遇到问题,实际上无法正确执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | import discord import tweepy from discord.ext import commands from tweepy import Stream from tweepy.streaming import StreamListener class TweetListener(StreamListener): def on_status(self, status): if status.in_reply_to_status_id is None: TweetText = status.text for DGuild in MyBot.guilds: for DChannel in DGuild.text_channels: if DChannel.name == 'testing': TwitterEmbed = discord.Embed(title='New Tweet', description='New Tweet from my timeline.', color=0xFF0000) TwitterEmbed.set_author(name='@TwitterHandle', icon_url=bot.user.default_avatar_url) DChannel.send(TweetText, embed = TwitterEmbed) DISCORD_TOKEN = 'dtoken' TWITTER_CONSUMER_KEY = 'ckey' TWITTER_CONSUMER_SECRET = 'csecret' TWITTER_ACCESS_TOKEN = 'atoken' TWITTER_ACCESS_SECRET = 'asecret' MyBot = commands.Bot(command_prefix='!', description='This is a testing bot') TwitterAuth = tweepy.OAuthHandler(TWITTER_CONSUMER_KEY, TWITTER_CONSUMER_SECRET) TwitterAuth.set_access_token(TWITTER_ACCESS_TOKEN, TWITTER_ACCESS_SECRET) TweetAPI = tweepy.API(TwitterAuth) NewListener = TweetListener() NewStream = tweepy.Stream(auth=TweetAPI.auth, listener=NewListener) NewStream.filter(follow=['USER IDS HERE'], is_async=True) @bot.event async def on_ready(): print(MyBot.user.name,'has successfully logged in ('+str(MyBot.user.id)+')') print('Ready to respond') MyBot.run(DISCORD_TOKEN) |
当我在测试帐户的时间轴上发布一条推文时,
1 | RuntimeWarning: coroutine 'Messageable.send' was never awaited |
我理解消息-
1 2 3 | async def on_status(self, status): <same code for checking the tweet and finding the channel> await DChannel.send(TweetText, embed = TwitterEmbed) |
但这总是导致类似的警告:
1 2 | RuntimeWarning: coroutine 'TweetListener.on_status' was never awaited if self.on_status(status) is False: |
我发现了一个问题,如何从tweepy同步on_status?并按照那里的链接进行操作,但是我看不到任何导致我出现编码错误的原因。
通过其他研究,我还尝试使用
1 2 3 4 5 | #channel.send(message, embed = TwitterEmbed) #---ASYNCIO TEST--- loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.gather(DChannel.send(embed=TwitterEmbed))) loop.close() |
不幸的是,当它尝试执行指示
我意识到已经有像MEE6这样的现有Discord机器人已经可以完成我在这里想要做的事情,但是我希望能够在自学一点的同时使它成为"我自己的"机器人关于Python。我可能在这里忽略了一些简单的内容,但是我无法在API文档中找到
环境信息
Visual Studio 2017 CE
Python 3.6
discord.py 1.3.3
tweepy 3.8.0
更新:附加测试
因此,为了向我证明我的
我还尝试以同步模式而不是异步方式初始化
即使如此,只是为了看看它是否会有所作为,我继续注释了Discord交互代码,然后再次尝试。结果与我最初的结果相同,只是这次Discord机器人不会响应通道中的活动(代码中的其他地方有几个超简单的
我敢肯定,有更好的方法来编码整个内容。就像我在上面说的,我现在才开始使用Python并仍在学习语法规则等。即使这样,我仍然不确定自己在做错什么,并且/或者忽略了这一点,这使我无法实现我认为是相当简单的任务。
更多测试
我回过头来,发现了更多的
中的Discord交互中尝试了另一次迭代。
1 2 3 | loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) result=loop.run_until_complete(DChannel.send(embed=TwitterEmbed)) |
这次,我遇到了与以前不同的未处理异常。当它收到一条新的tweet时,该错误发生在
1 | Timeout context manager should be used inside a task |
我考虑了这一进展,但是显然我还没有到位,因此回到Google时,我发现
1 | asgiref.sync.async_to_sync(DChannel.send)(embed=TwitterEmbed) |
不幸的是,我得到了与
再来一轮
好吧,所以在查找有关我正在了解的
"好消息"是我发布推文时不再遇到任何错误。另外,测试bot命令似乎也可以正常工作。坏消息是它仍然没有将消息发送到频道。由于它不会产生任何错误,因此无法确定消息在何处结束。
我遇到了与您相同的问题,并从Google获得了确切的链接并尝试了所有链接,但正如您所提到的,没有任何作用。
因此,在我经过大量尝试和修改之后,我可以将主循环传递给tweepy侦听器,并使用run_coroutine_threadsafe执行异步功能。
这是我代码的要点:
收听者:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class EpicListener(tweepy.StreamListener): def __init__(self, discord, loop, *args, **kwargs): super().__init__(*args, **kwargs) self.discord = discord # this is just a function which sends a message to a channel self.loop = loop # this is the loop of discord client def on_status(self, status): self.send_message(status._json) def send_message(self, msg): # Submit the coroutine to a given loop future = asyncio.run_coroutine_threadsafe(self.discord(msg), self.loop) # Wait for the result with an optional timeout argument future.result() |
不和谐的客户:
1 2 3 4 5 6 7 8 9 10 | class MyClient(discord.Client): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) async def on_ready(self): myStream = tweepy.Stream( auth=api.auth, listener=EpicListener(discord=self.sendtwitter, loop=asyncio.get_event_loop()) ) myStream.filter(follow=['mohitwr'], is_async=True) print(myStream) |
希望这会有所帮助。