6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

木更津高専Advent Calendar 2024

Day 7

teamsがあまりよろしくないので学食botを作る

Last updated at Posted at 2024-12-06

この記事は木更津高専 Advent Calender 2024の7日目の記事です
前: Blenderとおでんの違い by @Nimono-sleep-well さん
後: CloudflareはDNSだけじゃない! by @toreis さん

経緯

teamsでpdfを開こうとするとたまに開けないことがある。学食にかかわらず開けない。というか結構な確率で開けない。ほんとにどうにかしてくれ
ということで普段使うチャットツールのDiscordのBOTでつくるか、となりました。

環境

  • discord.js 14.15.3
  • node.js 22.9.0
  • python 3.10.12

実装済み機能

  • 定期学食送信(平日20:00)
  • 今日と明日の学食の送信

pdfから学食のデータを取り出す

まず学校からteamsに投稿されている学食のpdfの表からデータをpdfplumberで抽出していく

import pdfplumber
import pandas as pd

pdf_path = "../data/1209.pdf" 
csv_path = "../data/output.csv"

# PDFから表を抽出
all_tables = []
with pdfplumber.open(pdf_path) as pdf:
    for page in pdf.pages:
        tables = page.extract_tables()
        for table in tables:
            # テーブルが空でないことを確認
            if table:
                df = pd.DataFrame(table[1:], columns=table[0])
                all_tables.append(df)

combined_df = pd.concat(all_tables, ignore_index = True)
combined_df.to_csv(csv_path, index = False, encoding = "utf-8")
print(f"{csv_path}に書き出しました")

# CSVファイルを読み込む
df = pd.read_csv(csv_path, encoding="utf-8", header=None)

pdf内の表を抽出してcsvファイルに書き出す

csvじゃ扱いづらいのでjsonに吐きだしていく
これがかなーーーーーーーーーーーーりやっっかい
学食のpdfはとてもとてもすばらしいのでよくわからない小さい文字が書かれている
これが原因でcsvの行と列がおかしなことになるしpdfごとに結果がことなる
たとえばかけ うどんそばこれがなんと

メニュー名 Mon Tue
かけ ~ ~
うどんそば ~ ~

といった二行にわかれていたり、わかれてなかったりと摩訶不思議なことが発生します
このバケモノpdfとなかよしになるのに開発全体の7割くらいもってかれました

from createCsv import df
import string
import json
import pandas as pd

menus = ["Aset", "Bset", "curry", "dailySpecialUdonSoba", "UdonSoba", "dailySpecialRamenPasta", "ramen"]
idenMenus = ["Aセット", "Bセット", "カレー", "日替り", "かけ", "日替り", "ラーメン"]
week = ["Mon", "Tue", "Wed", "Thu", "Fri"]
weekIndex = []
menusIndex = []

with open("../data/lunch.json", "r") as f:
    lunch = json.load(f)

col: int = 2
row: int = 2

#曜日からインデックスを取得
for i in week:
    while True:
        data: string = df.iloc[row][col]
        if pd.isna(data):
            data = "None"

        if i in data:
            weekIndex.append(col)
            break
        else:
            col += 1

col = 0
row = 0
#メニューの行のインデックスを取得
for i in idenMenus:
    while True:
        data: string = df.iloc[row][col]
        if pd.isna(data):
            data = "None"

        if i in data:
            menusIndex.append(row)
            row += 2
            break
        else:
            row += 1

for i in range(len(menus)):
    for j in range(len(week)): 
        if pd.isna(df.iloc[menusIndex[i]][weekIndex[j]]):
            (lunch[menus[i]][week[j]]) = "今日はありません"
        else:
            (lunch[menus[i]][week[j]]) = df.iloc[menusIndex[i]][weekIndex[j]]
        
        
with open("../data/lunch.json", "w") as f:
    json.dump(lunch, f,indent = 4 , ensure_ascii=False)

こんな感じで無理やりjsonに落しこみます

学食の表示

bot部分はdiscord.jsで書きます

const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
const lunch = require("../data/lunch.json");

const days = ["Mon", "Tue", "Wed", "Thu", "Fri"];
const dispMenu = ["Aセット", "Bセット", "カレー", "日替わりうどん・そば", "うどん・そば", "日替わりラーメン・パスタ", "ラーメン"];
const menu = ["Aset", "Bset", "curry", "dailySpecialUdonSoba", "UdonSoba", "dailySpecialRamenPasta", "ramen"];

module.exports = {
	data: new SlashCommandBuilder()
		.setName("tomorrow")
		.setDescription("明日の学食を表示します")
        .setDMPermission(false),
        async execute(interaction) {
            const today = new Date().getDay();
            if ((today+1) === 0 || (today+1) === 6) {
                await interaction.reply("明日は休日です。学食はありません");
                return;
            }
            const embed = new EmbedBuilder()
                .setTitle("明日の学食")
                .setDescription("明日の学食は以下の通りです")
                .setFooter({text: "※内容は変更される可能性があります"})
                .setTimestamp()
                dispMenu.forEach((item, index) => {
                    embed.addFields({
                        name: item,
                        value: lunch[menu[index]][days[today]],
                        inline: false
                    });
                });
            await interaction.reply({ embeds: [embed]});
        }
};

discordからみるとこんな感じ
image.png
おいしそう
今日の学食や毎日20:00に送信されるものも基本的にこの表示です
定期実行はcronをつかっています

cron.schedule("0 20 * * * ", async() => {
    const today = new Date().getDay();
    const embed = new EmbedBuilder()
        .setTitle("明日の学食")
        .setDescription("明日の学食は以下の通りです")
        .setFooter({text: "※内容は変更される可能性があります"})
        .setTimestamp()
        dispMenu.forEach((item, index) => {
            embed.addFields({
                name: item,
                value: lunch[menu[index]][days[today]],
                inline: false
            });
        });
        if ((today+1) === 0 || (today+1) === 6) {
            await interaction.channel.send("明日は休日です。学食はありません");
        }
        else {
            await interaction.channel.send({ embeds: [embed]});
        }    
});

実装したい機能

  • pdfの取得の自動化
  • アプリケーション
  • ファイル操作の自動実行

さいごに

pythonってすごい
学食はチゲうどんがいちばんおいしいです

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?