DiscordチャットボットをPythonでつくる (4) - チャットボットでメッセージを受信する
今回は、ようやくPythonを使ったチャットボット作成を始めていきます。
前回までの作業により、作業ディレクトリ discord-chatbot
内には少なくとも以下の2つが存在してることを確認してください。
.venv
ディレクトリ: 仮想環境用のディレクトリ
.discord_token
ファイル: Discordのトークンを記録したファイル
1. 仮想環境を有効化
-
discord-chatbot
ディレクトリに移動し、仮想環境を有効化します。cd discord-chatbot source .venv/bin/activate
-
discord.py
がインストールされていることも確認しておきましょう。pip list
2. チャットボットをDiscordに接続する
2.1. スクリプト作成
最初は単純に、Discordに接続するだけのチャットボットを作成します。
chatbot.py
という名前のファイルを作成し、その中に以下のコードを書いてください。
import discord
with open('.discord_token') as f:
token = f.read().strip()
intents = discord.Intents.default()
client = discord.Client(intents=intents)
client.run(token)
作成したスクリプトを実行してみましょう。
python chatbot.py
するとコンソールに以下のようなログが出力されるはずです。
“… has connected to Gateway” と書いてあります。ちゃんとDiscordに接続することが出来たようです。
2023-08-18 23:39:36 INFO discord.client logging in using static token
2023-08-18 23:39:37 INFO discord.gateway Shard ID None has connected to Gateway (Session ID: xxx).
停止するには Ctrl+C
を入力します。
2.2. コード解説
スクリプトの内容を一つずつ見ていきましょう。
1つ目
import discord
discord.py
を読み込んでいます。
2つ目
with open('.discord_token') as f:
token = f.read().strip()
これは.discord_token
に記載されているトークンを読み込み、 token
変数に代入しています。
末尾の改行を除去するために strip
を適用しています。
3つ目
intents = discord.Intents.default()
discord.Intents
はチャットボットにどのようなイベントの受信を許すかを定義するためのクラスです。
default()
となっておりデフォルト値を使用しています。とりあえず追求はせず、次に行きます。
4つ目
client = discord.Client(intents=intents)
discord.Client(...)
となっており、discordのクライアントを生成しています。
これがチャットボットの正体です。
5つ目
client.run(token)
トークンを使用してクライアントを起動しています。
これによりチャットボットが稼働を開始します。
3. チャットボットに機能を追加する
3.1 discord.Client
クラスを継承した独自のクラスを作成する
作成したチャットボットに機能を追加していきましょう。
discord.py
では様々な機能追加方法が用意されていますが、
このシリーズでは discord.Client
クラスを継承した独自のクラスを作成し、それに変更を加えていきます。
3.2 on_ready
メソッドと on_message
メソッド
先ほど作成した chatbot.py
を以下のように変更しましょう。
import discord
class MyClient(discord.Client):
async def on_ready(self):
"""Discord接続時に実行される関数."""
print(f'{self.user}として接続しました。')
async def on_message(self, message: discord.Message):
"""メッセージ受信時に実行される関数."""
print(f'{message.author}よりメッセージを受信しました: {message.content}')
with open('.discord_token') as f:
token = f.read().strip()
intents = discord.Intents.default()
client = MyClient(intents=intents)
client.run(token)
3.3 コード解説
MyClient
という名前のdiscord.Client
を継承したクラスを定義し、
on_ready
,on_message
という2つの関数をオーバーライドしています。- それぞれ以下の用途で使用されます:
on_ready
メソッド: Discord接続時に実行される関数on_message
メソッド: メッセージ受信時に実行される関数
- いずれの関数にも定義の先頭に
async
という文字列があります。
これらはコルーチン関数と呼ばれる非同期処理を行うための関数です。詳細は後日解説します。 self.user
にはボットのユーザ名が入っています。on_message
のmessage
引数には、discord.Message型のデータが入力されます。
message.author
はメッセージの送信者、message.content
はメッセージの内容が入っています。
f'{self.user}として接続しました。'
のように、先頭に f
が付く文字列が出てきます。
これはフォーマット済み文字列リテラル
またはf-string
と呼ばれるもので、
Python 3.6 より追加されました。(参照: フォーマット済み文字列リテラル)
文字列内に {self.user}
のように書くことで self.user
の値が表示されます。
format
メソッドよりも簡潔に書けて便利なので、このシリーズでは頻繁に使用していきます。
これは型ヒントと呼ばれるもので、コロンの右側に変数に入力される型の情報を記述します (Python 3.5 で追加)。
Pythonでは型の指定がなくても動作しますが、型ヒントを書いておくと様々なメリットがあります。
例えばVSCodeでコードを書く際に型ヒントがあると、message.
と打つだけでmessage.content
等の候補を表示してくれるためとても便利です。
3.4 実行してみる
-
それでは実行してみましょう。
python chatbot.py
-
すると、接続時に
xxxとして接続が完了しました。
といったメッセージがコンソール上に表示されます。 -
またチャットにメッセージを記入すると、
xxxよりメッセージを受信しました:
といったメッセージがコンソール上に表示されます。しかし、メッセージの内容が表示されていない!
3.5 メッセージの内容を受信できるように Intents の設定を変更する
なぜかメッセージの内容が表示されないので、ドキュメントを見てみましょう。
すると、以下のような記述がありました。
Intents.message_content
が有効化されていない場合は、ボットがメンションされている場合とDMである場合を除き、これは常に空文字列となります。
はい。先程スルーしていた discord.Intents
の設定が足りていませんでした。
メッセージの内容を受信するためには、intents.message_content
の値をTrue
に設定する必要があります。
intents.message_content = True
これを追加して再度スクリプトを起動し直してみましょう。
するとxxxよりメッセージを受信しました: yyy
のようにメッセージ内容が出力されるようになりました。
4. まとめ
今回は、チャットボットをDiscordに接続してユーザが入力したメッセージを受信するところまで行いました。
次回は受信したメッセージに対してチャット上で返信を行う設定を追加します。
今回作成したコード
import discord
class MyClient(discord.Client):
async def on_ready(self):
"""Discord接続時に実行される関数."""
print(f'{self.user}として接続しました。')
async def on_message(self, message: discord.Message):
"""メッセージ受信時に実行される関数."""
print(f'{message.author}よりメッセージを受信しました: {message.content}')
with open('.discord_token') as f:
token = f.read().strip()
intents = discord.Intents.default()
intents.message_content = True
client = MyClient(intents=intents)
client.run(token)