Help us understand the problem. What is going on with this article?

[Python]Discordで指定時間に発言させるBOT

はじめに

Disocordbotを指定時間に発言させたいけど
タスクスケジューラだったりcronだったりは使いたくないなー
どうせBOTは常時動いてるんだし内部で処理してくれたほうが嬉しいよねってことで作りました。

できること

タスクスケジューラ,cronを使わずに
DiscordのBOTに指定時間に発言させる。

環境

  • Python3.7
  • Discord.py 1.1.1

discordにBOTを導入するあれこれ

いろいろ参考になる記事がいっぱいあるのでこちらを参考に
Discord Botアカウント初期設定ガイド for Developer
Pythonで簡単なDiscord Botの作り方
Pythonで実用Discord Bot(discordpy解説)

ループ処理

時間判定をするために30秒置きに判定処理をループさせます。
ただ普通にtime.sleep()しちゃうとほかの処理が走らなくなっちゃうので
非同期処理のasyncio.sleep()を使おうかと思いましたが、
discord.pyにもっといいのがありました。
https://discordpy.readthedocs.io/ja/latest/ext/tasks/index.html

botを起動させる前に
このtasks.loopの処理を実行すればx秒ごとのループ実行ができる(らしい)

例えばloop()を60秒に1回実行する場合

tasksloop.py
#coding:UTF-8
import discord
from discord.ext import tasks

TOKEN = "**********" #トークン
CHANNEL_ID = ********** #チャンネルID
# 接続に必要なオブジェクトを生成
client = discord.Client()

# 60秒に一回ループ
@tasks.loop(seconds=60)
async def loop():
    channel = client.get_channel(CHANNEL_ID)
    await channel.send('時間だよ')  

#ループ処理実行
loop.start()
# Botの起動とDiscordサーバーへの接続
client.run(TOKEN)

上記の場合だと60秒に一回「時間だよ」と発言する。
どうしようもなく邪魔なbotができてしまいます。

指定時間に発言する

上記の方法を使って毎朝7:00に「おはよう」と発言するbotにする場合

ohayo-bot.py
#coding:UTF-8
import discord
from discord.ext import tasks
from datetime import datetime 

TOKEN = "**********" #トークン
CHANNEL_ID = ********** #チャンネルID
# 接続に必要なオブジェクトを生成
client = discord.Client()

# 60秒に一回ループ
@tasks.loop(seconds=60)
async def loop():
    # 現在の時刻
    now = datetime.now().strftime('%H:%M')
    if now == '07:00':
        channel = client.get_channel(CHANNEL_ID)
        await channel.send('おはよう')  

#ループ処理実行
loop.start()
# Botの起動とDiscordサーバーへの接続
client.run(TOKEN)

これで指定時間に発言させることができました。

今回作りたかったもの

「グラブルの古戦場やってると団アビリティ発動時間いつだっけ?ってなってたので
通知してくれるようなBOTを作ろうと思い作成に至りました。」
を実現したものも下記に置いておきます

コード詳細
danabiBot.py
#coding:UTF-8
import discord
from datetime import datetime
from discord.ext import tasks

TOKEN = "**********" #トークン
CHANNEL_ID = ********** #チャンネルID
# 接続に必要なオブジェクトを生成
client = discord.Client()


#投稿する日時
dateTimeList = [
'2019/05/19 19:00',
'2019/05/20 18:30',
'2019/05/21 18:30',
'2019/05/22 07:00',
'2019/05/23 07:00',
'2019/05/24 07:00',
'2019/05/25 07:00'
]

# 起動時に動作する処理
@client.event
async def on_ready():
    print('ready')

# 指定時間に走る処理
async def SendMessage():
    channel = client.get_channel(CHANNEL_ID)
    await channel.send('時間だよ')

# 30秒に一回ループ
@tasks.loop(seconds=30)
async def time_check():
    sleepTime = 0
    # 現在の時刻
    now = datetime.now().strftime('%Y/%m/%d %H:%M')
    if now in dateTimeList :
        print(now)
        await SendMessage()
        #該当時間だった場合は2重に投稿しないよう30秒余計に待機
        await asyncio.sleep(30)

# メッセージ受信時に動作する処理
@client.event
async def on_message(message):
    # メッセージ送信者がBotだった場合は無視する
    if message.author.bot:
        return
    # 使用できるコマンド一覧
    if message.content == '!help':
        await message.channel.send('現在使用できるコマンドはありません')

#ループ処理
time_check.start()
# Botの起動とDiscordサーバーへの接続
client.run(TOKEN)

さいごに

Schedulerとかも使いたかったけど、なんかあれね。うまくできなかった。
非同期処理との相性悪いとかなの?ぷろぐらむわかんない^p^

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした