컴퓨터/Python

python xlsm파일 grok 가공 vba 포함하기

풍경소리^^ 2025. 3. 12. 17:44
import pandas as pd
from openpyxl import load_workbook
import time
from datetime import datetime
import os
from openpyxl.utils import get_column_letter as column_letter

start_time = time.perf_counter()

# 상수 정의
SOURCE_FILE = r"G:\회사\인사\급여\2025급여\202502\2025년02월급여준비.xlsm"
TARGET_FILE = r"G:\회사\인사\급여\★급여대장이메일-현재test.xlsm"
SOURCE_SHEET = "4대급여"
TARGET_SHEET = "4대급여"
PAYSTUB_SHEET = "급여명세서사대보험"

# 파일 경로 확인
for file_path in [SOURCE_FILE, TARGET_FILE]:
    if not os.path.exists(file_path):
        raise FileNotFoundError(f"파일을 찾을 수 없습니다: {file_path}")

# ✅ 1️⃣ 원본 파일 읽기 및 처리
df = pd.read_excel(SOURCE_FILE, sheet_name=SOURCE_SHEET).fillna(0).rename(columns={'지급일': '년월'})
wb_source = load_workbook(SOURCE_FILE, data_only=True)
if SOURCE_SHEET not in wb_source.sheetnames:
    raise ValueError(f"시트 '{SOURCE_SHEET}'이(가) {SOURCE_FILE}에 없습니다!")
ws_source = wb_source[SOURCE_SHEET]
b2_value = ws_source["B2"].value
wb_source.close()
if not isinstance(b2_value, datetime):
    raise ValueError(f"B2 셀의 값이 날짜 형식이 아닙니다! 현재 값: {b2_value}")
year_month = int(b2_value.strftime("%Y%m"))
df['년월'] = year_month
df['사원코드'] = "임시"

# ✅ 2️⃣ 대상 파일 업데이트
wb_target = load_workbook(TARGET_FILE, keep_vba=True)
ws_target = wb_target[TARGET_SHEET]
ws_paystub = wb_target[PAYSTUB_SHEET]
if ws_target.max_row > 1:
    ws_target.delete_rows(2, ws_target.max_row)
ws_paystub["I2"] = year_month
ws_paystub["I3"] = b2_value.strftime("%Y-%m-%d")
for row in df.to_numpy().tolist():  # NumPy 배열을 리스트로 변환
    ws_target.append(row)

# ✅ 3️⃣ 카운터 열 추가
header = [cell.value for cell in ws_target[1]]
if "카운터" in header:
    counter_col = header.index("카운터") + 1
    for i, row_idx in enumerate(range(2, ws_target.max_row + 1), start=1):
        ws_target.cell(row=row_idx, column=counter_col, value=i)

# ✅ 4️⃣ 저장
try:
    wb_target.save(TARGET_FILE)
except Exception as e:
    print(f"❌ 파일 저장 실패: {e}")
    raise
finally:
    wb_target.close()

print("✅ 실행 완료! ⏳ 실행 시간:", round(time.perf_counter() - start_time, 2), "초")

 

차선책 xlsx로 저장하기

import pandas as pd
from openpyxl import load_workbook

# 기존 xlsm 파일 경로
xlsm_file_path = "./python_xlsm.xlsm"

# 새로운 xlsx 파일 경로
xlsx_file_path = "./python_xlsx.xlsx"

# 저장할 데이터프레임 생성
data = {
    "이름": ["to_excel", "이영희", "박민수"],
    "나이": [1, 30, 28],
    "부서": ["pandas", "개발", "마케팅"]
}
df = pd.DataFrame(data)

# 기존 xlsm 파일 불러오기 (VBA 매크로 없이)
wb = load_workbook(xlsm_file_path, keep_vba=False)

# 📌 "main" 시트 선택 & 기존 데이터 삭제
ws = wb["main"]
if ws.max_row >= 4:
    ws.delete_rows(4, ws.max_row - 3)

# 📌 새로운 xlsx 파일이 없으면 저장 (다른 시트 유지)
wb.save(xlsx_file_path)

# 📌 df.to_excel()을 사용하여 A4부터 데이터 입력
with pd.ExcelWriter(xlsx_file_path, engine="openpyxl", mode="a", if_sheet_exists="overlay") as writer:
    df.to_excel(writer, sheet_name="main", startrow=3, startcol=0, index=False, header=False)

print(f"저장 완료: {xlsx_file_path}")
# xlsx 파일로 저장 잘됨

 

vba 모듈을 별도로 백업

xlsx파일에 포함시켜 xlsm파일로 저장 - qwen

import os
import win32com.client as win32

def backup_vba_module(xlsm_file, backup_folder):
    """
    .xlsm 파일의 VBA 모듈을 백업합니다.
    :param xlsm_file: 원본 .xlsm 파일 경로
    :param backup_folder: 백업할 폴더 경로
    """
    if not os.path.isfile(xlsm_file):
        raise FileNotFoundError(f"지정된 파일을 찾을 수 없습니다: {xlsm_file}")

    excel = win32.Dispatch("Excel.Application")
    excel.Visible = False
    excel.DisplayAlerts = False

    workbook = None
    try:
        # .xlsm 파일 열기
        workbook = excel.Workbooks.Open(os.path.abspath(xlsm_file))

        # VBA 프로젝트 접근
        vba_project = workbook.VBProject

        # 백업 폴더가 없으면 생성
        if not os.path.exists(backup_folder):
            os.makedirs(backup_folder)

        # 각 모듈 백업
        for i in range(1, vba_project.VBComponents.Count + 1):
            component = vba_project.VBComponents.Item(i)
            module_name = component.Name

            # 모듈 유형 확인 (표준 모듈만 처리)
            if component.Type == 1:  # 1: vbext_ct_StdModule (표준 모듈)
                code_module = component.CodeModule
                if code_module.CountOfLines > 0:  # 비어 있지 않은 모듈만 처리
                    module_code = code_module.Lines(1, code_module.CountOfLines)

                    # 백업 파일로 저장
                    backup_file = os.path.join(backup_folder, f"{module_name}.bas")
                    with open(backup_file, "w", encoding="utf-8") as f:
                        f.write(module_code)
                    print(f"'{module_name}' 모듈이 백업되었습니다.")
                else:
                    print(f"'{module_name}' 모듈은 비어 있어 건너뜁니다.")
            else:
                print(f"'{module_name}'은 표준 모듈이 아니므로 건너뜁니다.")

        print(f"모든 VBA 모듈이 '{backup_folder}'에 백업되었습니다.")

    finally:
        if workbook:
            workbook.Close(SaveChanges=False)
        excel.Quit()


def insert_vba_module_into_xlsx(xlsx_file, backup_folder, output_xlsm_file):
    """
    백업된 VBA 모듈을 .xlsx 파일에 삽입하고 .xlsm 파일로 저장합니다.
    :param xlsx_file: 대상 .xlsx 파일 경로
    :param backup_folder: 백업된 VBA 모듈이 있는 폴더 경로
    :param output_xlsm_file: 결과로 저장될 .xlsm 파일 경로
    """
    if not os.path.isfile(xlsx_file):
        raise FileNotFoundError(f"지정된 파일을 찾을 수 없습니다: {xlsx_file}")
    if not os.path.exists(backup_folder):
        raise FileNotFoundError(f"백업 폴더를 찾을 수 없습니다: {backup_folder}")

    excel = win32.Dispatch("Excel.Application")
    excel.Visible = False
    excel.DisplayAlerts = False

    workbook = None
    try:
        # .xlsx 파일 열기
        workbook = excel.Workbooks.Open(os.path.abspath(xlsx_file))

        # VBA 프로젝트 접근
        vba_project = workbook.VBProject

        # 백업된 모듈 파일 목록 가져오기
        for module_file in os.listdir(backup_folder):
            if module_file.endswith(".bas"):
                module_name = os.path.splitext(module_file)[0]
                module_path = os.path.join(backup_folder, module_file)

                # 모듈 코드 읽기
                with open(module_path, "r", encoding="utf-8") as f:
                    module_code = f.read()

                # 새 모듈 추가
                new_component = vba_project.VBComponents.Add(1)  # 1: vbext_ct_StdModule
                new_component.Name = module_name
                new_component.CodeModule.AddFromString(module_code)

        # 결과 파일 저장 (.xlsm 형식으로)
        workbook.SaveAs(output_xlsm_file, FileFormat=52)  # 52: xlOpenXMLWorkbookMacroEnabled
        print(f"VBA 모듈이 삽입된 파일이 '{output_xlsm_file}'로 저장되었습니다.")

    finally:
        if workbook:
            workbook.Close(SaveChanges=False)
        excel.Quit()


# 예제 사용
if __name__ == "__main__":
    # 현재 디렉터리의 절대 경로를 기준으로 파일 경로 설정
    current_dir = os.getcwd()
    
    # 원본 .xlsm 파일 경로
    xlsm_file = os.path.join(current_dir, "python_xlsm.xlsm")
    
    # 백업 폴더 경로
    backup_folder = os.path.join(current_dir, "backup")

    # 대상 .xlsx 파일 경로
    xlsx_file = os.path.join(current_dir, "python_xlsx.xlsx")

    # 결과 .xlsm 파일 경로
    output_xlsm_file = os.path.join(current_dir, "output_with_vba.xlsm")

    # 1. VBA 모듈 백업
    backup_vba_module(xlsm_file, backup_folder)

    # 2. VBA 모듈 삽입 및 .xlsm 파일로 저장
    insert_vba_module_into_xlsx(xlsx_file, backup_folder, output_xlsm_file)

python_xlsm.xlsm
0.02MB