Discordプラットフォームは、音声通話、インスタントメッセージ、チャットルーム、メディア共有など、友人、家族、同僚とのコミュニケーションに必要なほぼすべての機能を備えています。そのため、このサービスが爆発的に人気を博したのも当然です。しかし、多くの新規ユーザーは、Discordボットがプラットフォームをさらに強力にできること、そして(既に)プログラマーでなくても比較的簡単に設定できることに気づいていません。
Discordを使ったことがある人なら、きっとDiscordボットに遭遇したことがあるでしょう。新しいサーバーに参加した時に歓迎してくれたり、ルールに違反した迷惑なユーザーを追い出してくれたりしたことがあるかもしれません。特定の単語にジョークやミームで自動返信するように設定されているものもあります。また、強力なDiscordボットの中には、特定のチャットのユーザーに、新型コロナウイルス感染症のワクチンの入手状況から、地元のゲームストアに最新のゲーム機が在庫にあるかどうかまで、あらゆる最新情報を提供してくれるものもあります。
ボットの機能や複雑さは多岐にわたります。既存のコードベースを入手することも可能ですが、独自のボットを作成したいという方もいるでしょう。ゼロからボットを作成する方法を学ぶことで、自分のニーズに合わせてカスタマイズできるようになるだけでなく、ボットの内部の仕組みを理解し、さらに重要な点として、問題が発生した際のトラブルシューティング方法を学ぶことができます。
そこで今日はPythonを使います。Pythonは、比較的読みやすいコードと組み込みの機能的なフォーマット機能(インデントは読みやすくするだけでなく、必須です!)のおかげで、コーディングを学びたい人にとって非常に良い最初の言語として知られています。始めるために必要なものは次のとおりです。
ちゃんとしたコンピューター。
Python のインストール。
統合開発環境 (IDE) - ここでコードを入力します。
Discord アカウントとサーバー。
コーヒー(オプションですが、強くお勧めします)。
ボットアプリケーションの作成
この記事を読んでいるということは、既にアカウントをお持ちで、Discordサーバーを運用している方を想定しています。そうでない場合は、サインアップしてサーバーを作成してください。作成が完了したら、開発者ポータルにアクセスしてください。左側の「アプリケーション」タブをクリックし、右上の「新規アプリケーション」ボタンをクリックしてください。

ここでは、ボット自体に名前を付けているわけではありません。これはボットを含むアプリケーションです。とはいえ、アプリケーションとボットに同じ名前を付けられない理由はありません。アプリケーションを作成したら、それをクリックし、サイドバーのボットリンクをクリックします。ここで、DiscordのBuild-A-Botプロセスを使用して、小さなロボットを作成できます。

ボットを作成すると、「ワイルドボットが登場しました!」というメッセージが表示されます。おめでとうございます!ボットが完成しました!誇りに思います。ボットに名前を付けると、ユーザー名欄の下にトークンセクションが表示されます。トークンはリンクの後ろに隠れています。
ボットトークンに関する注意事項
このトークンは秘密にして安全に保管することが重要です。トークンはボット固有の識別子であり、第三者がトークンを入手した場合、ボットを乗っ取られる可能性があります。また、トークンはボットに記述したコードを接続するための手段でもあります。トークンは非常に機密性の高い情報であるため、コード内に直接保存するのはあまり賢明ではありません。この点については後ほど説明します。
とりあえず、プレーンテキストエディタを開いてトークンを貼り付けてください。ボット関連の資料を保存する予定のフォルダに保存してください。後々混乱を避けるために、できればtoken.txtのような名前を付けてください。
ボットに権限を与える
次に、ボットに権限を付与します。ボットを開いたまま、サイドバーの「OAuth2」をクリックし、画面の「スコープ」セクションで「ボット」というボックスにチェックを入れ、「ボット権限」までスクロールして、いくつかの機能を設定します。チェックするボックスは自由に設定できます。下のスクリーンショットで私が選択したものは、決して強制ではありません。

ついでに、サイドバーのボットをもう一度クリックし、「特権ゲートウェイインテント」までスクロールダウンしてください。ボットがユーザーのプレゼンスに何らかの形で反応したり、メンバーリストを使用したりしたい場合は、以下の設定を有効にする必要があります。

ボットをサーバーに割り当てる
適切な権限を付与したら、「スコープ」ペインの下にあるリンクをコピーし、新しいブラウザタブを開いてアドレスバー/検索バーに貼り付け、Enterキーを押します。するとこの画面が表示されるので、ボットを追加するサーバー(または公式Python DiscordボットAPIでは「ギルド」と呼ばれるもの)を選択します。「続行」をクリックすると、そのサーバーにおけるボットの権限を確認する画面が表示されます。

補足:ボットの権限はサーバーごとに異なるため、ボットに付与されている権限を確認するには、そのサーバーから行う必要があります。権限を確認したい場合は、以下の手順に従ってください。Discordウィンドウの左上にあるサーバーを右クリックし、「サーバー設定」をクリックし、「統合」をクリックします。「ボットとアプリ」という見出しの下に、ボットが表示されます。これをクリックすると、ボットに付与したすべての権限が表示されます。権限を変更する場合は、「統合」ではなく「役割」をクリックし、ボットをクリックして、次の画面で「権限」タブに移動してください。
ボットに付与した権限を確認したら、「承認」をクリックすれば、完了です!これでボットが作成され、サーバーに割り当てられました。「ワイルドな[ボット名]が現れました」というメッセージが表示されます。さあ、ボットをプログラムしてみましょう!以前試してみて失敗したことがあるなら、おそらくここで諦めているでしょう。もう一度挑戦してみましょう。きっとうまくいきますよ。
ボットに命を吹き込む
続行するには、Pythonがインストールされていることを確認してください。インストール方法については多くのガイドがありますが、私はこちらをおすすめします。Pythonのセットアップが完了したら、Discordモジュールを入手する必要があります。このモジュールには、必要なDiscord固有のコマンドがすべて含まれています。Windowsの場合は、こちらに記載されている手順に従ってコマンドプロンプトを開き、以下のコマンドを入力してEnterキーを押してください。
py -3 -m pip インストール -U discord.py
macOS または Linux を使用している場合は、ターミナルを開いて次のように入力します。
python3 -m pip インストール -U discord.py
この手順が完了したら、お好みのIDE(統合開発環境)を開いてください。個人的にはSublimeが好きですが、お好きなIDEを使ってください。あるいは、ちょっと刺激的な気分なら、プレーンテキストエディタを使うのもいいでしょう。エディタを開いたら、新規ファイルを作成し、最初の行に以下を入力してください。
不和をインポート
これでDiscordライブラリがコードに導入されます。次に、ボットをこのコードに関連付ける方法が必要です。つまり、ボットのトークンを呼び出すということです。ただし、トークンをコード内に直接保存するのではなく、.txtファイルに保存するのが良いと言ったことを覚えていますか?次の行は、.txtファイルからトークンを取得する方法です。
TOKEN = open(“token.txt”,”r”).readline()
この行では、最初の変数を作成しています。これは、特定のアクションを参照するために入力できる文字列です。ここで、 TOKEN は変数で、 = 記号はコンピューターにその変数を何かとして解釈することを伝え、それに続くテキストがその何かです。ここで、 open() はコンピューターにファイルを開くことを伝え、括弧内は引数のペアです。最初の引数は開きたいファイルを特定します (ファイルを token.txt と呼ばなかった場合は、 token を任意の名前に置き換えます)。r はファイルを開くモードを指定します。トークンのみを読み取りたいので、 r を使用して読み取りモードで開きます。 .readline() 部分は、読み取る行を指定します。読み取る行は 1 行しかないため、括弧内は空のままにします。
Discordの意図
Discord がボットのイベントサブスクリプションの処理方法に最近変更が加えられたため、メンバーの参加など、特定のイベントにボットが応答できるようにするには、いくつか追加の手順が必要です。Discord ではこれらの特別な権限インテントを「特権インテント」と呼び、ユーザー監視などのより高レベルの権限インテントは「特権インテント」(前の手順で切り替えた可能性のあるトグル)と呼ばれます。ボットのセットアップ時にこれらのインテントを有効にするだけでなく、コードでもインテントを有効にする必要があります。まず、デフォルトのイベントサブスクリプションで実行したい場合は、インテントをデフォルトとして定義します。
インテント = discord.Intents.default()
次に、必要な追加インテントのいずれかをTrueに設定します。また、すべてのデフォルト設定は不要で、ボットが反応するイベントの種類を限定したい場合もあるでしょう。その場合は、上記の設定の代わりに、以下のように設定できます。
インテント.メンバー = True
インテント.メッセージ = True
intents.guilds = True
このセクションの最後のステップは、クライアントを定義し、次のことを確認することです。
クライアント = discord.Client(インテント = インテント)
プログラミングアクション
さて、これでボットに何をすべきか指示する準備が整いました。まず、ソフトウェアが正常にログインしたことを確認するために、print() ステートメントを追加すると便利です。このコードは、ボットが接続され実行中であることを確認するステートメントをランタイム環境(ターミナルなど)に出力(表示)します。
@クライアントイベント
非同期定義on_ready():
print('{0.user}としてログインしました'.format(client))
ここで async を使用する理由は、Python がデフォルトで同期型であるためです。つまり、コマンドを実行し、完了するまで待ってから次の処理に進みます。サーバーとの通信では、必ずしも同期型にする必要はありません。サーバーが停止した場合など、プログラムも停止してしまうからです。後続のコードがそのコード行に全く依存していない場合は、プログラムの他のコードを実行させ続けるのが良いでしょう。そこで、サーバーが他のコードの実行を継続できるように、async(非同期の略)を使用します。Discord が応答すると、コードは中断したところから再開し、使用した非同期ハンドラー(この場合は on_ready())の後に記述されたステートメントを実行します。
次に、ボットにコマンドに応答させる方法を見ていきましょう。例として、ボットに「こんにちは」と挨拶させてみましょう。まず、メッセージハンドラーを呼び出す必要があります。
@クライアントイベント
非同期定義on_message(メッセージ):
次に、ボットが自分自身に応答しないようにするために、ボットが何かを言ったらアクションなしでコードを返すようにします。
message.author == client.user の場合:
戻る
最後に、ボットの応答を促すコマンド:
message.content.startswith('.hello'): の場合
message.channel.send('Hello!') を待機します。
したがって、ブロック全体をまとめると次のようになります。
@クライアントイベント
非同期定義on_message(メッセージ):
message.author == client.user の場合:
戻る
message.content.startswith('.hello'): の場合
message.channel.send('Hello!') を待機します。
もちろん、ここでのループ防止コードは厳密には不要です。ボットがここで自分自身に応答し続けることはまずありません。しかし、コードが複雑になるにつれて、意図せずボットをプログラムしてしまい、自己トリガーを起こして応答を繰り返すサイクルに陥ってしまう可能性があります。例えば、ランダムに映画の名言を拾うボットを作成し、トリガーワードの1つが、引用ライブラリから取得した引用文の中に含まれていた場合などです。
次のコードにより、ボットはウェルカムメッセージを送信できます。コードの先頭で有効化したインテントは、ボットがメンバーリストを監視する必要があるため必須です。Discordはこれを特権インテントと見なします。
@クライアントイベント
非同期定義 on_member_join(member):
print('何かを手に入れた')
channel = client.get_channel([ここにチャンネルIDを記入])
await channel.send('このチャンネルへようこそ!')
ここで重要な点がいくつかあります:
このprint文はデバッグのためにあります。ウェルカムメッセージをテストしていた時、ダミーアカウントでDiscordサーバーに参加・退出させていましたが、なかなかウェルカムメッセージを表示できませんでした。そこで、async def on_member_join(member): が実際にプログラムを起動して後続のコードを実行するかどうかを確認するために、print文を挿入しました。もし実行されていれば、ターミナル上でprint文は「何かが見つかりました」と表示されるはずです。しかし、実際には実行されていなかったので、デバッグする必要がありました。結局、重要なコード行は一番最初の方にありました。
クライアント = discord.Client(インテント = インテント)
このコードは、ボット(クライアント)が私が付与した権限を取得するために必要でした。これを行うには、上記の括弧内に、ボットのインテントをコードの先頭で定義した値と同じ値に設定する引数を指定します。もちろん、このコード行全体を省略していたため、ボットは実際には私が有効にしたインテントを使用していませんでした。
チャンネルIDを取得するには:IDを取得したいチャンネルにアクセスしたら、アドレスバーにURLと、それに続く2つの長い数字列(/で区切られています)が表示されます。2つ目の数字列がチャンネルIDで、1つ目の数字列がサーバーIDまたはギルドIDです。上記の引数でチャンネルIDを使用してください。
最後に、このコードセットの await コンポーネントは、非同期処理を使用する場合に必要です。ボットが応答する場合、サーバーが最終的に応答したときに何をすべきかを知るための何らかのコールバック関数が必要です。await はその機能を果たし、この場合は、事前に定義したチャネルで「このチャネルへようこそ!」というメッセージをボットに送信するように指示します。
適切な(そして非常に必要な!)フォーマットをすべて施した最終的なコードを見てみましょう。

明かりを灯し続ける
おそらく、ボットを常に稼働させておきたいと思うでしょう。そのためにはいくつかの方法があります。まず、自宅のメインのコンピューターからボットを実行するという方法がありますが、その場合、コンピューターを常にオンにして接続状態を維持し、スリープ状態にしておく必要が出てきます(コンピューターがWake on LANに設定されていれば、技術的にはスリープ状態にできますが、この機能は面倒で予測不可能な動作をする可能性があります)。
より良い選択肢としては、Raspberry Piなどの低消費電力の専用サーバーマシンでコードを実行することが考えられます。基本的に、*.py プログラムをサーバー上で実行し、すべてがうまくいけば、プログラムは不確定な時間だけ実行されます。最初のうちはこれで問題ありません。ボットが複雑になり、(許可すれば)他のDiscordサーバーでも使用されるようになると、おそらく24時間365日に近い稼働を望むようになるでしょう。そのためには、サードパーティのホスティングサービスを検討する必要があります。無料と有料のオプションは数多くあり、こちらにその手助けとなる、分かりやすく詳細なガイドがあります。
これで完了です!この基本的なコマンドセットで、機能的なボットが完成しました。もちろん、ボットを使って自動化できる機能は他にもたくさんあります。Stack Overflowやdiscord.py APIを調べてみるのも良いでしょう。ボットは、管理者の業務をはるかに楽にする自動化機能など、思いのままに強力に活用できます。あるいは、ちょっとした名言集や、友達とシェアする小さなDiscordサーバーでのちょっとした余興として使うこともできます。いずれにせよ、ボットはDiscordサーバーを管理するだけでなく、コーディングの重要な知識を学ぶ楽しい方法でもあります。