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)
