학교 업무 자동화 - 스프레드시트로 평가 계획서 초안 제작 자동화

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

2022개정 교육과정이 들어오면서 과목이 많아지고, 이에 따라 평가 계획서도 매 학기마다 새롭게 써야하는 일이 생겼다.

문제는 평가 계획서에는 각 단원별 성취 기준, 성취 수준 등을 모두 기재해야하는 요식 행위를 필요로 한다는 것이다.

이런 기준들은 따로 교사가 작성하는 것이 아니라 단순히 복사+붙여넣기를 하는 것.

그래서 해당 내용들을 테이블로 정리한 뒤, 엑셀이나 스프레드시트의 FILTERTEXTJOIN 함수를 이용해 자동으로 합쳐보기로 했다.

1. 성취수준 데이터베이스 만들기

각 선택교과 당 성취수준은 아래의 KICE 학생평가지원포털에서 얻을 수 있다.

상단 목차의 [초/중/고] -> [교육과정 성취기준] -> [성취기준 자료실] 에서 검색한 뒤 다운받으면 된다.

예를들어 세계시민과 지리의 성취수준을 보며 아래와 같다.

문제는 이런 성취 기준이 적게는 15개이고, 각 성취 기준마다의 성취 수준을 복사해서 A~E까지 합쳐야 한다는 것이다.

이제 이 자료들을 테이블로 만들어 보자.

학교 업무 자동화 - 스프레드시트로 평가 계획서 초안 제작 자동화-1

먼저 hwp로 되어 있는 파일을 hwpx 파일로 만들어준다.

hwpx파일은 내부 파일 구조를 xml 데이터로 저장하기 때문에 다른 프로그램으로 내부를 파싱할 수 있게 해준다.

학교 업무 자동화 - 스프레드시트로 평가 계획서 초안 제작 자동화-2

그리고 파이썬을 이용해 hwpx 내부의 테이블을 뽑아내 본다.

아래 코드는 당연히 chatGPT 형님의 도움을 받았다.

hwpx 파일은 zip + xml 구조이므로 파이썬으로 내부 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

그냥 엑셀에서 필터와 텍스트 나누기를 이용해 각각 성취기준 코드, 내용, 성취기준별 성취수준을 분리시켰다.

이를 정규화를 하면 성능은 올라가겠지만, 사람이 확인하기는 어렵기에 그냥 중복된 컬럼으로 두기로 했다.

그리고 이렇게 만들고 나니, 차라리 데이터베이스 공개 청구를 할걸 그랬나 하는 생각도 든다.

2. 스프레드시트 만들기

일반적인 학교들은 평가 계획에 각 주차에 맞는 성취코드와 성취 기준을 넣는다.

그래서 월별로 성취코드만 선택하면 자동으로 채워지도록 만들면 평가 계획 입력이 훨씬 쉬워질 것이라 생각했다.

스프레드시트는 filterunique 함수를 이용해 입력하려고 하는 과목, 단원, 성취코드를 조합해 만들었다.

만약 어렵다면 AI와 함께 만들어보길 권해본다.

학교 업무 자동화 - 스프레드시트로 평가 계획서 초안 제작 자동화-4

첫번째 탭에서는 월, 주차, 단원명, 성취기준코드를 입력하면 가장 오른쪽에서 붙여넣기만 하면 되도록 만들어보았다.

가운데 있는 초록색 박스 부분은 내가 넣은 성취기준을 확인하기 위해 만들어 두었다.

이렇게 선택을 해주면 단원별 성취기준 및 성취수준, 학기 단위 성취 수준이 모두 완성되도록 만들었다.

학교 업무 자동화 - 스프레드시트로 평가 계획서 초안 제작 자동화-5

사실 일반적인 교과에서는 모든 성취기준을 평가 계획에 넣으니 그냥 다 때려박아도 상관 없지만, 교육과정 재구성을 고려해서 제작했다.

그냥 A~E를 모두 합쳐주는 시트도 한번 넣어볼까 고민중이다.

그리고 수행평가를 위한 시트도 하나 만들어 보았다.

학교 업무 자동화 - 스프레드시트로 평가 계획서 초안 제작 자동화-6

내가 수행평가에 넣고싶은 성취기준 코드를 넣으면, 평가 계획서에 넣을 수 있도록 A~E 수준을 모두 합쳐준다.

우리가 고민해야 할 부분은 복사, 붙여넣기가 아니라 실질적으로 어떤 평가가 이루어져야 할 것인지이다.

3. 사용 후기

학교 업무 자동화 - 스프레드시트로 평가 계획서 초안 제작 자동화-7

안타깝게도 많은 교사들이 평가 계획에 시간을 쏟아부음에도 불구하고, 교실에 있는 사람들은 그 누구도 성취 수준의 문장을 궁금해 하지 않는다.

평가 계획 보다는 평가 계획에 따라 구현되는 평가 그 자체가 중요하기 때문이다.

성취 기준을 평가 기준에 넣기 시작했던 시기부터 졸업한 사람들에게, 성취 기준이 무엇이었는지 물어본다면그 누구도 기억하지 못할 것이라고 자신있게 말할 수 있다.

그래서 평가 기준에 이러한 문장들을 넣는 것이 의미 없는 요식 행위일 뿐이라고 말할 수 있을 것이다.

학교에서 이루어지는 교육 현장은 성취 코드, 성취 기준 따위 처럼 정적인 것이 아니라 동적이다.

우리는 평가 계획의 공문서적 완성도 보다는, 평가 자체의 질적인 문제를 고민해야 하는 시간이 더 필요하지 않은가 하는 생각이 든다.

아마 제대로 된 사용 후기는 실제로 사용한 뒤인 7~8월 이후에나 올릴 수 있을 것 같다.

옆자리 선생님께 이 스프레드 시트를 공유했더니, 지금 당장 2학기 평가 계획을 만둘수 있을 것 같다며 좋아하셨다.

아마 많은 도움이 되지 않을까 싶다.

관련 글

2026년 동국대학교 미래사회 교원역량 강화 포럼 오프라인 참여 후기
2026년 동국대학교 미래사회 교원역량 강화 포럼 오프라인 참여 후기
어느 선생님이 재미있어 보이는 연수를 하나 소개시켜 주셨다.동국대에서 진행하는 AI 관련 연수였다.AI인 것도 좋인데 연수가 호텔에서?이건 무조건 가야 한다 싶었다.해당일 연수가 열리자 마자 신청해서 오프라인으로 참석하게 되었다.1. 앰배서더 서울 풀만 호텔처음에는 접...
대한민국 교육박람회(2026) 방문 후기
대한민국 교육박람회(2026) 방문 후기
어쩌다가 인스타그램을 통해 대한민국 교육박람회에 대한 행사 정보를 얻게 되었다.작년에는 다른 행사와 겹쳐 가지 못했기에, 올해는 꼭 가보고 싶었다.그래서 바로 사전 예약을 했다.사전 예약자는 입장료가 8,000원, 현장 등록자는 15,000원 이다.아는 분 말씀으로는 ...
2022 개정 교육과정 지구과학 내용 미리보기 - 3단원 태양계 천체와 별과 우주의 진화
2022 개정 교육과정 지구과학 내용 미리보기 - 3단원 태양계 천체와 별과 우주의 진화
이번에는 지구과학 둘러보기 마지막.3단원을 살펴보려고 한다.1. 내용체계3단원의 내용 체계는 이전 지구과학1의 천체 단원에서 외계 행성과 생명체 탐사가 빠지고 지구과학2에 있던 태양계 모형과 일식과 월식이 새로 들어왔다. 다른 단원들보다는 내용이 상당히 축소된 느낌이다...
국가교육위원회, 고교학점제 이수 기준 개편
국가교육위원회, 고교학점제 이수 기준 개편
[본 기사는 라이브 영상을 이용해 AI로 제작된 기사입니다.]출결 중심 vs 성취도 반영… “지원 대책 없는 제도 확정은 위험”국가교육위원회가 고교학점제 이수 기준 개편을 두고 본격적인 논의에 들어갔다. 출결률을 중심으로 할 것인지, 학업 성취도를 함께 반영할 것인지를...
교사를 위한 교육연구 및 통계분석 연수 - 21~30차시 정리, 그리고 후기 등
교사를 위한 교육연구 및 통계분석 연수 - 21~30차시 정리, 그리고 후기 등
오늘은 교사를 위한 교육연구 및 통계분석 연구의 21~30차시에서 기억나는 내용과 후기를 남겨보려고 한다.1. logit(로짓)과 로지틱스 회귀분석처음에 로지틱스 회귀분석이라길래 뭔가 대단한것인줄 알았는데, 알고보니 로짓을 따라가는 선형 회귀분석이었다.예전에 LLM을 ...
교사를 위한 교육연구 및 통계분석 연수 - 13~20차시 R 실습 모음
교사를 위한 교육연구 및 통계분석 연수 - 13~20차시 R 실습 모음
이전에는 파이썬을 할 줄 아는데 굳이 R을 배워야 하는가에 대한 의문이 있었다.이번 연수를 들으며, 연구할 때 굳이 파이썬을 쓸 필요가 없다는 것을 깨닫게 되었다.파이썬 같으면 numpy로 선형회귀하고, 그래프 그리고, P value 구하고 다 해야 하지만 R은 lm과...

댓글을 불러오는 중...