
Pythonで雀魂の対局結果を自動集計する⑤
こんにちは!カツキチです。
前回、対局結果画像から抽出した名前、素点、順位点をOneDriveの Excelに記録し、過去の結果を集計して表示するプログラムが完成しました。
しかし今のままではDiscordにアップされた画像を手でプログラムに渡し、出力された結果をDiscordに手で投稿しなければなりません。
Discordとの自動連係をするにはどうしたら良いのだろう、、、眠れない日々が続きました(約1日)。
Discordと自動連携する
私が参加するDiscordには頼もしい人たちが大勢います。雑談していたところ、yabukilabさんという方が有用な情報をくれました。
なるほど、PythonだとDiscordのBOTも作れてしまうのですね、スゴすぎる。
実装するにあたり、フローを考えました。Discord.pyは単体のプログラムで動作させる想定です。
Discordのサーバーにログインする
雀魂チャンネルに画像がアップロードされたらURLを取得する
結果抽出プログラムに画像のURLを渡す
結果抽出プログラムの結果をDiscordに投稿する
なお、Discordにログインや投稿をするためのBOTアカウントを作成し、ログインしたいサーバーの管理権限を与える必要があります。手順は前述のサイトの通りです。管理権限はサングルサーバの管理者であるコージ師範に付与していただきました、感謝!
Discord連携プログラム Ver 0.1
Dicord.pyは2022年5月にメジャーバージョンアップがあったようです。新バージョンの情報が少ないため、結構苦戦しました。
テスト用のサーバーで試行錯誤を繰り返し、アップロードした画像のURLを投稿するプロトタイププログラムを作成しました。
from discord.ext import commands
import discord
# Discordの権限設定
intents = discord.Intents.default()
intents.members = True # メンバー管理の権限
intents.message_content = True # メッセージの内容を取得する権限
bot = commands.Bot(
command_prefix="$", # $コマンド名 でコマンドを実行できるようになる
case_insensitive=True, # 大文字小文字を区別しない
intents=intents # 権限を設定
)
# Discordにログイン
@bot.event
async def on_ready():
print(f"Logged in as {bot.user.name}")
# 投稿を確認
@bot.event
async def on_message(message: discord.Message):
# BOTのメッセージは無視
if message.author.bot:
return
# ターゲットのチャンネルID
target_channel_id = xxxxxxxxxxxxxxxx # 練習用チャンネル
# 投稿されたメッセージが特定のチャンネルIDの場合
if message.channel.id == target_channel_id:
# ファイルが添付されている場合
if message.attachments:
# 添付ファイルごとに処理
for attachment in message.attachments:
# 画像のURLをDiscordに投稿
await message.reply(attachment)
# BOTのアクセストークン
bot.run('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX') # maskしています
ライブラリは以下の手順でインストールします。
PS > pip install discord.py
さて、プロトタイプを実行してみます。
PS > python.exe .\sample.py
2025-02-22 20:29:58 INFO discord.client logging in using static token
2025-02-22 20:30:00 INFO discord.gateway Shard ID None has connected to Gateway (Session ID:XXXXXXXXXXXXXXXXXXXXXX X).
Logged in as カツキチBOT
この状態でDiscordの練習用チャンネルに画像をアップロードしてみます。

うまく行きました!
Discord連携プログラム Ver 1.0
subprocessライブラリを使って画像のURLを結果抽出プログラムに渡すように変更して、完成です。
from discord.ext import commands
import discord
import subprocess
# 結果抽出プログラム
result_py = './result.py'
# Discordの権限設定
intents = discord.Intents.default()
intents.members = True # メンバー管理の権限
intents.message_content = True # メッセージの内容を取得する権限
bot = commands.Bot(
command_prefix="$", # $コマンド名 でコマンドを実行できるようになる
case_insensitive=True, # 大文字小文字を区別しない
intents=intents # 権限を設定
)
# Discordにログイン
@bot.event
async def on_ready():
print(f"Logged in as {bot.user.name}")
# 投稿を確認
@bot.event
async def on_message(message: discord.Message):
# BOTのメッセージは無視
if message.author.bot:
return
# ターゲットのチャンネルID
target_channel_id = xxxxxxxxxxxxxxxx # 麻雀チャンネル
# 投稿されたメッセージが特定のチャンネルIDの場合
if message.channel.id == target_channel_id:
# ファイルが添付されている場合
if message.attachments:
# 添付ファイルごとに処理
for attachment in message.attachments:
# 結果抽出プログラムを実行
command = ["python", result_py, str(attachment)]
proc = subprocess.run(command, capture_output=True, text=True)
print("標準出力:")
print(proc.stdout)
# 標準出力のみDiscordに投稿
await message.reply(proc.stdout)
print("\n標準エラー出力:")
print(proc.stderr)
# BOTのアクセストークン
bot.run('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX') # maskしています
大成功!

これでようやく、最初に定義した大まかなフローが完成しました!
(対局した人が)対局結果のスクリーンショットをDiscordにアップする
アップしたスクリーンショット画像から名前、素点、順位点を抽出する【完成】
抽出した情報を記録する【完成】
記録した情報から当月の対局結果をDiscordに投稿する【完成】
やっと完成した・・・。余韻に浸りながらパソコンを閉じた時、気づいてしまったのです。
これ、パソコン落としたら実行されないじゃん・・・
パソコンを起動せずとも、このプログラムを常時実行するにはどうしたらよいものか。
次回へ続きます。