学校業務の自動化 - スプレッドシートで評価計画書のドラフト作成を自動化

힘센캥거루
2026년 3월 30일(수정됨)
6
33

2022改訂教育課程が導入されてから科目が増え、それに伴って評価計画書も毎学期ごとに新しく作成しなければならなくなった。

問題は、評価計画書には各単元別の達成基準や達成水準などをすべて記載しなければならないという形式的な手続きが必要だという点である。

しかしこうした基準は、教師が一から作成するのではなく、単純にコピー&ペーストしているだけだ。

そこで、該当内容をテーブルとして整理したうえで、Excel やスプレッドシートの FILTERTEXTJOIN 関数を使って自動的に結合してみることにした。

1. 達成水準データベースを作る

各選択教科ごとの達成水準は、下記の KICE 学生評価支援ポータルで取得できる。

上部メニューの[初/中/高] -> [教育課程達成基準] -> [達成基準資料室] で検索してダウンロードすればよい。

例えば「世界市民と地理」の達成水準を見ると、次のようになっている。

問題は、このような達成基準が少ないものでも 15 個ほどあり、各達成基準ごとに達成水準をコピーして A〜E までまとめなければならないということだ。

では、この資料をテーブルにしてみよう。

学校業務の自動化 - スプレッドシートで評価計画書のドラフト作成を自動化-1

まず hwp 形式のファイルをhwpx ファイルに変換する。

hwpx ファイルは内部ファイル構造を XML データとして保存しているため、他のプログラムで内部をパースできるようになる。

学校業務の自動化 - スプレッドシートで評価計画書のドラフト作成を自動化-2

そして Python を使って hwpx 内部のテーブルを抽出してみる。

以下のコードは、もちろん chatGPT 兄貴の助けを借りて作成した。

hwpx ファイルは zip + xml 構造なので、Python で内部の xml を読み取り、テーブルを抽出できる。

// 이 코드는 생성형 AI를 이용해 제작한 코드입니다.

import zipfile
import xml.etree.ElementTree as ET
from openpyxl import Workbook

hwpx_path = "사회과 선택과목 성취수준 현장 보급본.hwpx"
xlsx_path = "output.xlsx"


def tag_name(elem):
    return elem.tag.split("}")[-1]


def collect_text(node):
    texts = []

    # tc 내부에 중첩 tbl이 있으면 그 하위 텍스트는 제외한다.
    stack = [node]
    while stack:
        cur = stack.pop()

        if cur is not node and tag_name(cur) == "tbl":
            continue

        if tag_name(cur) == "t" and cur.text:
            t = cur.text.strip()
            if t:
                texts.append(t)

        children = list(cur)
        stack.extend(reversed(children))

    return "\n".join(texts)


def is_title_like(text):
    if not text:
        return False

    compact = text.replace(" ", "")

    # 표 전체 내용을 붙여 놓은 긴 문장은 제목으로 취급하지 않는다.
    if len(text) > 80:
        return False

    # 표 헤더/본문 키워드가 포함되면 제목 행으로 넣지 않는다.
    if "성취기준" in compact and "성취수준" in compact:
        return False

    return True


wb = Workbook()
ws = wb.active
ws.title = "tables"

saved_table_count = 0
current_row = 1

with zipfile.ZipFile(hwpx_path, "r") as z:
    section_files = sorted(
        name for name in z.namelist()
        if name.startswith("Contents/section") and name.endswith(".xml")
    )

    for section_file in section_files:
        xml_data = z.read(section_file)
        root = ET.fromstring(xml_data)

        elems = list(root.iter())

        for i, elem in enumerate(elems):
            if tag_name(elem) != "tbl":
                continue

            tbl = elem

            prev_text = ""
            for j in range(i - 1, -1, -1):
                if tag_name(elems[j]) != "p":
                    continue

                texts = []
                for x in elems[j].iter():
                    if tag_name(x) == "t" and x.text:
                        t = x.text.strip()
                        if t:
                            texts.append(t)

                candidate = " ".join(texts)
                if not candidate:
                    continue

                if is_title_like(candidate):
                    prev_text = candidate
                    break

            table_rows = []
            for tr in tbl:
                if tag_name(tr) != "tr":
                    continue

                row_values = []
                for tc in tr:
                    if tag_name(tc) != "tc":
                        continue
                    row_values.append(collect_text(tc))

                if row_values:
                    table_rows.append(row_values)

            if not table_rows:
                continue

            preview_text = "".join(table_rows[0])

            # 1행 1셀 같은 요약성/오검출 표는 제외한다.
            has_enough_shape = len(table_rows) >= 2 and any(len(r) >= 2 for r in table_rows)

            if "성취기준별" in preview_text and "성취수준" in preview_text and has_enough_shape:
                saved_table_count += 1

                table_title = prev_text if is_title_like(prev_text) else ""

                for row_values in table_rows:
                    # 1열에는 표 제목을 두고, 실제 표 데이터는 오른쪽(2열부터) 배치한다.
                    ws.cell(row=current_row, column=1, value=table_title)

                    first_value = row_values[0].strip() if row_values and isinstance(row_values[0], str) else ""
                    start_col = 3 if first_value in {"B", "C", "D", "E"} else 2

                    for col_idx, value in enumerate(row_values, start=start_col):
                        ws.cell(row=current_row, column=col_idx, value=value)

                    # 오른쪽으로 밀린(B/C/D/E) 행은 표의 첫 번째 열(2열)을 바로 윗행 값으로 채운다.
                    if start_col == 3 and current_row > 1:
                        ws.cell(row=current_row, column=2, value=ws.cell(row=current_row - 1, column=2).value)

                    current_row += 1

                # 표 사이 한 줄 띄우기
                current_row += 2

if saved_table_count == 0:
    ws["A1"] = "조건에 맞는 표를 찾지 못했습니다."

wb.save(xlsx_path)
print(f"완료: {saved_table_count}개 표를 하나의 시트에 저장")

こうすると、内部テーブルが次のように抽出される。

それでもうまく抽出されない表がある場合は、手作業でデータを少しだけ整形しよう。

学校業務の自動化 - スプレッドシートで評価計画書のドラフト作成を自動化-3

単純に Excel でフィルターと区切り位置(テキスト分割)を使って、それぞれ達成基準コード、内容、達成基準別の達成水準を分離した。

これを正規化すれば性能は上がるだろうが、人が確認するにはかえってわかりづらくなるので、そのまま重複したカラムの状態にしておくことにした。

そしてここまで作ってみると、いっそデータベースの公開請求をすればよかったのでは、という気もしてくる。

2. スプレッドシートを作る

一般的な学校では、評価計画に各週に対応する達成コードと達成基準を入れる。

そこで、月ごとに達成コードだけ選べば自動的に埋め込まれるようにすれば、評価計画の入力がかなり楽になるだろうと考えた。

スプレッドシートは filterunique 関数を使って、入力しようとする科目・単元・達成コードを組み合わせて作成した。

もし難しく感じるなら、AI と一緒に作ってみることをおすすめしたい。

学校業務の自動化 - スプレッドシートで評価計画書のドラフト作成を自動化-4

最初のタブでは、月、週、単元名、達成基準コードを入力すると、一番右側でコピー&ペーストするだけでよいように作ってみた。

中央の緑色のボックス部分は、自分が入力した達成基準を確認するために作っておいたものだ。

このように選択さえすれば、単元別達成基準および達成水準、学期単位の達成水準がすべて完成するようにしてある。

学校業務の自動化 - スプレッドシートで評価計画書のドラフト作成を自動化-5

実のところ、一般的な教科ではすべての達成基準を評価計画に入れるので、そのまま全部突っ込んでしまっても構わないが、教育課程の再構成を考慮して作成した。

単に A〜E をすべて結合してくれるシートも一つ入れてみようかと悩んでいるところだ。

また、パフォーマンス評価用のシートも一つ作ってみた。

学校業務の自動化 - スプレッドシートで評価計画書のドラフト作成を自動化-6

自分がパフォーマンス評価に入れたい達成基準コードを入力すると、評価計画書に入れられるように A〜E 水準をすべて結合してくれる。

私たちが悩むべきなのは、コピー&ペーストではなく、実質的にどのような評価が行われるべきかという点である。

3. 使ってみた感想

学校業務の自動化 - スプレッドシートで評価計画書のドラフト作成を自動化-7

残念ながら多くの教師たちは、評価計画に多くの時間を注ぎ込んでいるにもかかわらず、教室にいる誰一人として達成水準の文章に関心を持たない。

評価計画そのものよりも、評価計画に基づいて実際に行われる評価そのものが重要だからだ。

達成基準を評価基準に書き込むようになってから卒業した人たちに、達成基準が何だったのか尋ねたとしても、誰一人として覚えていないだろうと断言できる。

だから、評価基準にこうした文章を入れることは、意味のない形式的な行為に過ぎないと言えるだろう。

学校で行われている教育の現場は、達成コードや達成基準といった静的なものではなく、動的なものである。

私たちは評価計画という公文書の完成度よりも、評価そのものの質的な問題について考える時間が、もっと必要なのではないかと思う。

おそらく、きちんとした使用レビューは、実際に使ってみたあとの 7〜8 月以降にしか書けないだろう。

隣の席の先生にこのスプレッドシートを共有したところ、今すぐにでも 2 学期の評価計画を作れそうだと喜んでおられた。

きっと多くの人の役に立つのではないかと思う。

관련 글

模擬試験一覧表が大教協、ユニブ、キム・ヨンイルにアップロードできないとき - PDFで保存
模擬試験一覧表が大教協、ユニブ、キム・ヨンイルにアップロードできないとき - PDFで保存
模擬試験を受けた後、評価院で成績表を印刷物、またはPDF形式で出力することができる。PDFで受け取ったファイルを見ると、たまに内部にデータがまったくなく、画像としてだけ存在している場合があり、そのときは成績を処理するのがとても厄介だ。このような場合は、どれだけ入試プログラムに成績をアップロードしよう...
学校の教室でのロボット掃除機の運用方法
学校の教室でのロボット掃除機の運用方法
教室でロボット掃除機を使い始めて、もう4年になる。今年は、私がロボット掃除機を気にかけるのではなく、子どもたちが完全に管理できるようにすることが目標だ。1. ロボット掃除機を運用する意外で不思議だったのは、ロボット掃除機を一度も掃除したことがない子どもが多いということだ。ダストボックスを空にし、裏側...
2026年 東国大学 未来社会 教員力量強化フォーラム オフライン参加レビュー
2026年 東国大学 未来社会 教員力量強化フォーラム オフライン参加レビュー
ある先生が、面白そうな研修を一つ紹介してくださった。東国大で行われるAI関連の研修だった。AIに関する研修というだけでも良いのに、会場がホテルだって?これは絶対に行かなきゃと思った。当日、研修の募集が始まるとすぐに申し込んで、オフラインで参加することになった。1. アンバサダーソウル プルマンホテル...
学校業務の自動化 - AIを利用した生活記録簿チェック 教科別・特別記述編
学校業務の自動化 - AIを利用した生活記録簿チェック 教科別・特別記述編
学校で最も意味がなく、きつくて退屈な業務を一つ挙げろと言われたら、自分は生活記録簿(生徒指導要録)チェックを選ぶだろう。中学校では生活記録簿がそれほど重要ではないが、高等学校では入試と関係しているため非常に重要である。問題は、このような生活記録簿の点検で探すものが、せいぜい単純な誤字脱字、記載禁止用...
大韓民国教育博覧会(2026)訪問記
大韓民国教育博覧会(2026)訪問記
ふとしたきっかけで、インスタグラムを通じて大韓民国教育博覧会のイベント情報を知った。昨年は別のイベントと日程が重なって行けなかったので、今年こそはぜひ行きたいと思っていた。そこでさっそく事前予約をした。事前予約者の入場料は8,000ウォン、当日登録は15,000ウォンである。知り合いによると教員は入...
2022改訂教育課程 地球科学内容プレビュー - 第3単元 太陽系天体と恒星・宇宙の進化
2022改訂教育課程 地球科学内容プレビュー - 第3単元 太陽系天体と恒星・宇宙の進化
今回は地球科学の概観もいよいよ最後である。第3単元を見ていこうと思う。1. 内容体系第3単元の内容体系は、以前の「地球科学1」の天体単元から系外惑星と生命体探査が抜け、代わりに「地球科学2」にあった太陽系モデルと日食・月食が新たに入ってきた。他の単元に比べると、内容がかなり縮小された印象だ。2. 第...

댓글을 불러오는 중...