Discord Botの作り方 ~基礎から実用まで~
はじめに
こんにちは、Sattです。
今回は、discord.pyを使った実用的なDiscord botの作り方を紹介しようと思います。noteやQiitaにもbotに関する記事がたくさん上がっていますが、どれも基礎的か発展的な事項のみのものが多く、参考にしづらかったため、この記事を作成した次第です。
なお、筆者はPython&discord.py歴が1か月もないため、見苦しいコードではありますが、放念していただきたいです。
準備
Discord Developer Portalでbotを登録する
Discordでbotを作るために、まずDiscord Developer Portalで自分のbotを登録し、サーバーに招待する必要があります。
下のやり方と参考画像を見ながら行ってください。
Discordアカウントでログイン。
右上の"New Application"のボタンを押して新しくアプリケーションを作成する。
NAMEの欄に任意の名前を入れ、Createを押す。
左のメニューからBotを選び、少しスクロールすると"Privileged Gateway Intents"というオプションがあるので、その下にある三つの設定を全てオンにする(これをしないと、botが動かない可能性があります)。
左のメニューからOAuth2を選び、"OAuth2 URL Generator"の中の"SCOPES"から"bot"を選ぶ。
"BOT PERMISSIONS"から"Administrator"(設定は楽になるが、botを乗っ取られた際の危険性が上がる)か"TEXT PERMISSIONS"と"VOICE PERMISSIONS"の中にある全ての設定(サーバー管理はできなくなるが、安全性が上がる)をオンにする。
一番下の"GENERATED URL"からリンクをコピーし、botを任意のサーバーに招待する。
これで、招待の部分は完了です。
Pythonをインストールする
Visual Studio Codeをインストールする
これは言うまでもないと思うので、ダウンロードリンクだけつけておきます。
Python ダウンロード
Visual Studio Code ダウンロード
どちらもインストールが終わったら、Visual Studio Code(以下VSCode)を開き
Open Folder…を押して、任意のフォルダを開いてください。
基礎
まずは、元となる"main.py"から作っていきましょう。VSCodeで、右上のメニューから先ほどのフォルダに"main.py"という名前のファイルを作り、
import discord
from discord.ext import commands
from atproto import Client # type: ignore
import json
import pretty_help
from pretty_help import PrettyHelp
import datetime
initial_extensions = (
)
description = '''こんにちは!'''
# チャンネル指定
Manage_Channel = # ここに管理用チャンネルのIDを挿入
# ずんだもん
zunda = 'https://i.imgur.com/6bgRNLR.png'
# helpコマンドのembedの下の文字
ending_note = "Pasted from Satt \nFor help: {help.clean_prefix}{help.invoked_with}"
class MyBot(commands.Bot):
def __init__(self):
intents = discord.Intents.all()
super().__init__(command_prefix='!', #コマンドの前に付く記号を指定
description=description, # 概要欄
intents=intents,
help_command=PrettyHelp(menu=pretty_help.AppMenu(),
index_title="助けが必要ですか?", # embedのタイトル
color= 0x191919, # 色
ending_note=ending_note, # フッター
thumbnail_url=zunda, # サムネイル
send_typing=False,
sort_commands=True
)
)
async def setup_hook(self) -> None: # ログインする前に実行されるイベント
await bot.load_extension("jishaku") # jishakuをロードする
for extension in initial_extensions: #cogをロードする
try:
await self.load_extension(extension)
except Exception as e:
print(e)
print(f"Failed to load extension {extension}.")
async def on_ready(self): # 起動時に実行されるイベント
print(f'{self.user.name}#{self.user.discriminator} ({self.user.id})としてログインしました!')
channel = bot.get_channel(Manage_Channel)
await channel.send(f'botが起動しました! @{datetime.datetime.now().strftime("%H:%M:%S")}')
bot = MyBot()
# tokenをロード
bot_token = ''
with open("data/!important/bot_token.json", "r", encoding="utf-8") as f:
bot_token = json.load(f)
bot.run(bot_token)
以上のコードを書いてください。
次に、botのtokenをDiscord Developer Portalから入手します。
左のメニューからbotを開いて、TOKENから"Reset token"のボタンを押して、tokenをコピーします。
そして、VSCodeに戻り、先ほどのフォルダにdataフォルダ、その下に!importantフォルダを作り、その中にbot_token.jsonを作成します。コピーしたtokenをダブルクォーテーション(")で囲んで保存します。ᅠ
このようなフォルダ構成になっていれば正解です。
上のメニューから"Terminal"を選んで、
pip install discord.py
pip install jishaku
pip install discord-pretty-help
をそれぞれ実行します。
discord.pyは名前のまま、botの基本となっているもの、jishakuとdiscord-pretty-helpはそれの拡張機能のようなものです。jishakuの使い方は後々説明します。
ここまでくれば、あとは実行するだけです!先ほど使用した"Terminal"で
python main.py
を実行し少し待てば、Manage_Channelで指定したチャンネルに"botが起動しました! @XX:XX:XX"と表示されるはずです。
任意のチャンネルで、"!help"を送った際に、
このように表示されたら成功です!
これで基礎は終了です。次の章では、実際の機能を追加していきます。
コマンドに反応する機能
先ほどの"!help"のような、コマンドに応答する機能はかなり基本的なもので、簡単に作ることができます。
フォルダ内にcogsフォルダを作成し、その中にcommand.pyを作ります。
このような構成になると思います。
そして、command.pyの中に
import discord
from discord.ext import commands
import random
from atproto import Client # type: ignore
import asyncio
import json
from cogs.diyembed import diyembed
# 磨かれるもののリスト
items = [
"歯", "靴", "金属(例えば、銀)", "宝石", "車のボディ", "鏡", "メガネ", "木材",
"陶器", "ステンレス", "ガラス", "メタルフィギュア", "時計", "銅製品", "銀器",
"磁器", "照明器具", "スチール", "アルミニウム", "レザー製品", "チタン", "金",
"ステンレス製のカトラリー", "アクセサリー", "タイル", "プラスチック", "銅線",
"シルバーアクセサリー", "ノートパソコンの表面", "スマートフォン", "カメラレンズ",
"音楽機器", "彫刻", "家具", "イヤリング", "ブレスレット", "リング", "ペンダント",
"スポーツ用具", "自転車のフレーム", "ヘルメット", "メダル", "ビンの口",
"磨き仕上げされた石", "アート作品", "眼鏡のフレーム", "すり鉢", "すりこぎ",
"鋼材", "磨かれた大理石", "自動車部品", "ドアノブ", "銀のカップ", "風鈴",
"酒器", "スポーツカップ", "ペンケース", "織物の装飾", "磨き上げられたトロフィー",
"工具", "アンティーク家具", "鉄製品", "電子機器の筐体", "金属製の装飾品", "ホイール",
"キッチン用品", "スポーツウェア(光沢加工されたもの)", "襟章", "高級筆記具",
"研磨剤で磨かれた木彫り", "革製のベルト", "ステンレス製の調理器具", "スポーツボトル",
"美術品のフレーム", "メタルパーツ(機械の一部)", "陶磁器", "木製の楽器",
"高級タバコケース", "ビリヤードのキュー", "船の部品", "武道の装備",
"楽器の金属部分", "医療機器", "スポーツ用具(クラブなど)", "カメラのボディ",
"音響機器", "装飾的な金属パーツ", "磨き上げられた真鍮製品", "釣り具",
"高級ワインのボトル", "名刺入れ", "電気器具", "金属製の家具部品", "高級な鍵",
"アートのフレーム", "スポーツのメダル", "車のホイールリム", "歴史的な硬貨",
"装飾的な宝飾品", "高級時計のケース"
]
# cogを作成
class command(commands.Cog): # commandはcogの名前(ファイル名と同じにすると良い)
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
@commands.command()
async def migaku(self, ctx):
migaku_item = random.choice(items)
await ctx.reply(f'今日は**{migaku_item}**を磨きましょう')
async def setup(bot: commands.Bot):
await bot.add_cog(command(bot))
を入力し、main.pyの
initial_extensions = (
)
この部分を
initial_extensions = (
"cogs.command", # ロードするcogを選択
)
これに書き換えてください。
さて、突然ですが、このbot制作においてはdiscord.pyのcogという機能を使っているので、botが起動しているときに新しいcogを作ったとしても、起動した状態のままロードすることができます。早速やってみましょう。
任意のチャンネルで!jsk load cogs.commandと送って、
このように返答が返ってきたら成功です。こうならなかった場合は、手順のどこかで間違ったことになります。その後、!migakuと送るとリプライが返ってくるはずです。
他にも、任意の文字列から始まるメッセージに反応させたかったら
@commands.Cog.listener()
async def on_message(self, message):
if message.author == self.bot.user or message.author.bot:
return
if message.content.startswith('[ここに任意の文字列を挿入]'):
await message.channel.send('[レスポンス]')
これを先ほどの@commands.commandの群の下に挿入すればできますし、
if message.content.startswith('[ここに任意の文字列を挿入]'):
を
if '[ここに任意の文字列を挿入]' in message.content:
に変えれば部分一致に、
if message.content =='[ここに任意の文字列を挿入]':
に変えれば完全一致になります。
これらや、discord.pyの公式docsを参考にしつつ拡張していっていただければと思います。
おわり
終