# Discord py 機器人初學筆記 ###### tags: `Python` `Discord` --- [TOC] ## 1. 建立基本機器人架構 ### Step 1: 申請 Discord 帳號,並到 Discord Developer - https://discord.com/developers ### Step 2: 建立一架新的機器人,並複製 Token :::info :bulb: **Token 很重要,需善加保存** ![](https://hackmd.io/_uploads/SkAblhBUh.png) ::: ### Step 3: 撰寫基本架構 - 需先於終端機打上 ==pip install discord== ```python= import discord from discord.ext import commands intents = discord.Intents.all() bot = commands.Bot(command_prefix='/',intents=intents) @bot.event async def on_ready(): print(">>{} is online!".format(bot.user)) bot.run("Token") ``` --- ## 2. Message 用法 ### Step 1: 建立架構 ```python= @bot.event async def on_message(): await ``` ### Step 2: 回復訊息功能 ```python= @bot.event async def on_message(message): if message.content == "你好": await message.channel.send("嗨"+ str(message.author)) ``` :::info :bulb: 機器人會從訊息找到你的資料,並跟你打招呼~ ![](https://hackmd.io/_uploads/SJtKB3r83.png) ::: ### Step 3: 避免機器人自己回覆自己 ```python= @bot.event async def on_message(message): if message.author == bot.user: await if message.content == "你好": await message.channel.send("嗨"+ str(message.author)) ``` :::warning :warning: 如果沒有這樣設定的話,可能會導致無限輪迴 ::: ## 3. Json 用法 ### Step 1: 在同一個資料夾內,建立一個新的 json 檔 ```jsonld= { "Token" : "打上自己的 Token" } ``` :::info :bulb: 每一筆資料之間都要用==逗點==隔開 ::: :::warning :warning: 新增資料時要注意資料型態,json 的字串宣告需用雙引號 ::: ### Step 2: 在 bot.py 裡引用並開啟 json ```python= import json with open("名稱.json","r", encoding = "utf8") as file: jfile = json.loads(file) #此時 jfile 存取了 json 裡面的資料 ``` :::info :bulb: 上述用法須在 json 與 bot.py 在同一個資料夾才能使用 ::: :::warning :warning: 注意 load 與 loads 的用法差別,兩個不一樣 ::: ### Step 3: 利用 json 將 Token 隱藏起來 ```python= import discord import json from discord.ext import commands with open("settings.json", "r", encoding = "utf8") as file: jfile = json.load(file) # 從 settings.json 取得資料 intents = discord.Intents.all() bot = commands.Bot(command_prefix='/',intents=intents) @bot.event async def on_ready(): print(">>{} is online!".format(bot.user)) bot.run(jfile["Token"]) # 將 Token 隱藏起來 ``` ## 4. 成員加入 / 退出訊息 ### Step 1: 建立基本架構 ```python= @bot.event async def on_member_join(member): #成員加入 await @bot.event async def on_member_remove(member): #成員退出 await ``` ### Step 2: 列印出成員名稱&編號 ```python= @bot.event async def on_member_join(member): #成員加入 print("{} 加入".format(member)) @bot.event async def on_member_remove(member): #成員退出 print("{} 退出".format(member)) ``` :::info :bulb: 這邊的 print 是在終端機上列印,不是在頻道裡列印 ::: ### Step 3: 在頻道發出加入 / 退出訊息 ```python= @bot.event async def on_member_join(member): #成員加入 channel = bot.get_channel("頻道ID") await channel.send("{} 加入".format(member)) @bot.event async def on_member_remove(member): #成員退出 channel = bot.get_channel("頻道ID") await channel.send("{} 退出".format(member)) ``` :::info :bulb: 頻道 ID 也能用 json 存起來哦,但是要記得轉成 int ::: ## 5. 建立基本指令 (延遲查詢) ### Step 1: 建立基本架構 ```python= @bot.command() async def ping(ctx): # ctx 代表上下文 await ``` :::info :bulb: ping 在這邊代表指令名稱,呼叫的時候可以在頻道打 /ping ::: ### Step 2: 延遲功能 ```python= @bot.command() async def ping(ctx): # ctx 代表上下文 await ctx.send("{}".format(bot.latency)) ``` ### Step 3: 優化 ```python= @bot.command() async def ping(ctx): # ctx 代表上下文 await ctx.send("{} (ms)".format(round(bot.latency * 1000))) ``` #### 效果如下 :arrow_down: :clap: ![](https://hackmd.io/_uploads/SJLbYs4Dh.png) ## 6. 傳送圖片功能 (利用 url) ### Step 1: 建立基本架構 ```python= @bot.command() async def pic(ctx): await ctx.send("圖片網址") ``` ### Step 2: 隨機傳送圖片 ```python= import random l1 = {"圖片網址1","圖片網址2"} @bot.command() async def pic(ctx): r_pic = random.choice(l1) await ctx.send(r_pic) ``` ### Step 3: 配合 json #### Json 如下 :arrow_down: ```jsonld= { "picture" : ["圖片網址1","圖片網址2"] } ``` #### python 如下 :arrow_down: ```python= import random import json with open("settings.json","r",encoding= "utf8") as file: jfile = json.load(file) @bot.command() async def pic(ctx): r_pic = random.choice(jfile["picture"]) await ctx.send(r_pic) ``` #### 效果如下 :arrow_down: :clap: ![](https://hackmd.io/_uploads/ByYa_jED2.png) ## 7. 指令 Cog 實作 ### Step 1: 建立一個資料夾 core 與建立 classes.py #### Classes 如下 :arrow_down: ```python= import discord from discord.ext import commands class Cog_Extension(commands.Cog): def __init__(self,bot): self.bot = bot ``` ### Step 2: 建立一個資料夾 cmds 與建立 main.py 與 react.py #### main 如下 :arrow_down: ```python= import discord from discord.ext import commands from core.classes import Cog_Extension #從 core 裡面的 classes 引入 Cog_Extension class Main(Cog_Extension): @commands.command() #這邊要用 commands async def ping(self,ctx): # ctx 代表上下文 await ctx.send("{} (ms)".format(round(self.bot.latency * 1000))) #由於我們已將self.bot 定義成 bot,所以這邊要用 self.bot async def setup(bot): # 這邊的 bot 是 bot.py 裡面定義的 bot await bot.add_cog(Main(bot)) # 呼叫功能 add_cog 並傳入 bot ``` #### react 如下 :arrow_down: ```python= import discord import random from discord.ext import commands from core.classes import Cog_Extension #從 core 裡面的 classes 引入 Cog_Extension with open("data.json","r",encoding="utf8") as file: jfile = json.load(file) class React(Cog_Extension): @commands.command() async def pic(self,ctx): r_pic = random.choice(jfile["picture"]) await ctx.send(r_pic) async def setup(bot): # 這邊的 bot 是 bot.py 裡面定義的 bot await bot.add_cog(React(bot)) # 呼叫功能 add_cog 並傳入 bot ``` ### Step 3: 修改 bot.py #### bot 如下 :arrow_down: ```python= import discord import json import random from discord.ext import commands import os import asyncio with open("data.json","r",encoding="utf8") as file: jfile = json.load(file) intents = discord.Intents.all() bot = commands.Bot(command_prefix="/",intents=intents) @bot.event async def on_ready(): print("> Bot is online") @bot.event async def on_member_join(member): channel = bot.get_channel(int(jfile["join_channel"])) await channel.send("{} join!".format(member)) @bot.event async def on_memeber_remove(member): channel = bot.get_channel(int(jfile["leave_channel"])) await channel.send("{} leave!".format(member)) @bot.command() #讀取 Extension async def load(ctx,extension): await bot.load_extension("cmds.{}".format(extension)) await ctx.send("Loaded {} done.".format(extension)) @bot.command() #卸載 Extension async def unload(ctx,extension): await bot.unload_extension("cmds.{}".format(extension)) await ctx.send("Un-loaded {} done.".format(extension)) @bot.command() #重新讀取 Extension async def reload(ctx,extension): await bot.reload_extension("cmds.{}".format(extension)) await ctx.send("Reloaded {} done.".format(extension)) async def main(): for filename in os.listdir("./cmds"): if filename.endswith(".py"): await bot.load_extension("cmds.{}".format(filename[:-3])) await bot.start(jfile["token"]) #由於 bot.run 只能用在程式的結尾,而 bot.start 能在協程後面 if __name__=="__main__": #避免呼叫的時候執行 asyncio.run(main()) ``` #### 效果如下 :arrow_down: :clap: ##### 1.分類表 ![](https://hackmd.io/_uploads/B13iPsEP2.png) ##### 2.將 Main 卸載 ![](https://hackmd.io/_uploads/rkJQOsVv2.png) ##### 3.將 Main 讀取 ![](https://hackmd.io/_uploads/HyGvujVvn.png) ##### 4.將 Main 重新讀取 ![](https://hackmd.io/_uploads/BkzLAsVDh.png) ## 8. 事件 Cog 實作 ### Step 1: 在 cmds 內建立 event.py #### event 如下 :arrow_down: ```python= import discord import json from discord.ext import commands from core.classes import Cog_Extension with open("data.json","r",encoding="utf8") as file: jfile = json.load(file) class Event(Cog_Extension): @commands.Cog.listener() async def on_member_join(self,member): channel = self.bot.get_channel(int(jfile["join_channel"])) await channel.send("{} join!".format(member)) @commands.Cog.listener() async def on_memeber_remove(self,member): channel = self.bot.get_channel(int(jfile["leave_channel"])) await channel.send("{} leave!".format(member)) @commands.Cog.listener() async def on_message(self,message): if message.content.startswith("hi"): await message.channel.send("hello") async def setup(bot): await bot.add_cog(Event(bot)) ``` :::info :bulb: 在 Cog 裡面,需用 @commands.Cog.listener() ::: ### Step 2: 優化 on_message 功能 ```python= @commands.Cog.listener() async def on_message(self,message): if message.content.startswith("hi"): await message.channel.send("hello {}".format(message.author)) ``` #### 效果如下 :arrow_down: :clap: ##### 回復功能 ![](https://hackmd.io/_uploads/H11nP2NP3.png) ## 9. 所有檔案 #### bot.py ```python= import discord import json import random from discord.ext import commands import os import asyncio with open("data.json","r",encoding="utf8") as file: jfile = json.load(file) intents = discord.Intents.all() bot = commands.Bot(command_prefix="/",intents=intents) @bot.event async def on_ready(): print("> Bot is online") @bot.command() async def load(ctx,extension): await bot.load_extension("cmds.{}".format(extension)) await ctx.send("Loaded {} done.".format(extension)) @bot.command() async def unload(ctx,extension): await bot.unload_extension("cmds.{}".format(extension)) await ctx.send("Un-loaded {} done.".format(extension)) @bot.command() async def reload(ctx,extension): await bot.reload_extension("cmds.{}".format(extension)) await ctx.send("Reloaded {} done.".format(extension)) async def main(): for filename in os.listdir("./cmds"): if filename.endswith(".py"): await bot.load_extension("cmds.{}".format(filename[:-3])) await bot.start(jfile["token"]) if __name__=="__main__": asyncio.run(main()) ``` #### event.py ```python= import discord import json from discord.ext import commands from core.classes import Cog_Extension with open("data.json","r",encoding="utf8") as file: jfile = json.load(file) class Event(Cog_Extension): @commands.Cog.listener() async def on_member_join(self,member): channel = self.bot.get_channel(int(jfile["join_channel"])) await channel.send("{} join!".format(member)) @commands.Cog.listener() async def on_memeber_remove(self,member): channel = self.bot.get_channel(int(jfile["leave_channel"])) await channel.send("{} leave!".format(member)) @commands.Cog.listener() async def on_message(self,message): if message.content.startswith("hi") and message.author != self.bot.user: await message.channel.send("hello {}".format(message.author)) async def setup(bot): await bot.add_cog(Event(bot)) ``` #### main.py ```python= import discord import json from discord.ext import commands from core.classes import Cog_Extension class Main(Cog_Extension): #繼承 Cog 類別 @commands.command() async def ping(self,ctx): # ctx 代表上下文 await ctx.send("{} (ms)".format(round(self.bot.latency * 1000))) async def setup(bot): await bot.add_cog(Main(bot)) ``` #### react.py ```python= import discord import json from discord.ext import commands from core.classes import Cog_Extension import random with open("data.json","r",encoding="utf8") as file: jfile = json.load(file) class React(Cog_Extension): #繼承 Cog 類別 @commands.command() async def pic(self,ctx): r_pic = random.choice(jfile["picture"]) await ctx.send(r_pic) async def setup(bot): await bot.add_cog(React(bot)) ``` #### classes.py ```python= import discord import json from discord.ext import commands class Cog_Extension(commands.Cog): def __init__(self,bot): self.bot = bot ``` #### data.json ```python= { "token": "MTA4NzA2OTQ4ODMwMzg0NTM3Ng.GKa7We.l3bC_c0W5RiUktYVo5l19KDyoNc4EjoXfjZRhs", "join_channel": "1086638861213499433", "leave_channel": "1086638911280922624", "picture": [ "https://th.bing.com/th/id/R.ecc5b5e754b520dc955cff152f934cae?rik=q%2bWWYRBHNo3ROw&pid=ImgRaw&r=0", "https://th.bing.com/th/id/R.6e9b001ffd29f4013ad85232a900e746?rik=l3eaBT97IM6YNA&pid=ImgRaw&r=0", "https://th.bing.com/th/id/OIP.0M0PB0odBhmSNPZsksgWFAAAAA?w=204&h=204&c=7&r=0&o=5&dpr=1.3&pid=1.7" ] } ``` [ToC] * 官方文件: