컴퓨터/Python

python pandas로 기존 xlsm xlsx 파일 수정 vba유지

풍경소리^^ 2025. 3. 26. 12:29

deepseek

import pandas as pd
from openpyxl import load_workbook
import os

def update_excel_sheets(file_path, sheet_updates, output_path=None, start_row=0, start_col=0, include_header=False):
    """경로 문제를 해결한 최종 버전"""
    # 절대 경로로 변환 (중복 경로 제거)
    file_path = os.path.abspath(file_path)
    print(f"실제 접근 경로: {file_path}")  # 디버깅용 출력
    
    if output_path is None:
        output_path = file_path
    else:
        output_path = os.path.abspath(output_path)
    
    # 확장자 확인
    ext = os.path.splitext(file_path)[1].lower()
    is_xlsm = (ext == '.xlsm')
    
    try:
        # 파일 로드
        book = load_workbook(file_path, keep_vba=is_xlsm)
        existing_sheets = book.sheetnames
        
        with pd.ExcelWriter(
            output_path,
            engine='openpyxl',
            mode='a',
            if_sheet_exists='overlay'
        ) as writer:
            writer._book = book
            writer._sheets = {ws.title: ws for ws in book.worksheets}
            
            for sheet_name, df in sheet_updates.items():
                if sheet_name not in existing_sheets:
                    ws = book.create_sheet(sheet_name)
                    writer._sheets[sheet_name] = ws
                else:
                    ws = book[sheet_name]
                    # 기존 데이터 삭제 (선택적)
                    if start_row > 0 or start_col > 0:
                        for row in ws.iter_rows(min_row=start_row+1, min_col=start_col+1):
                            for cell in row:
                                cell.value = None
                
                # 새 데이터 쓰기
                df.to_excel(
                    writer,
                    sheet_name=sheet_name,
                    index=False,
                    startrow=start_row,
                    startcol=start_col,
                    header=include_header
                )
        
        print(f"파일 저장 완료: {output_path}")
    
    except FileNotFoundError:
        print(f"⚠️ 오류: 파일을 찾을 수 없습니다. 경로를 확인하세요.\n{file_path}")
    except Exception as e:
        print(f"⚠️ 예상치 못한 오류: {str(e)}")

# 사용 예시 (3가지 경로 지정 방법)
# 방법 1: 절대 경로 직접 지정 (추천)
file_path = "test.xlsx"
# file_path = r"B:\python\pandas\pandas_xlsm\test.xlsm"

# 방법 2: os.path.join() 정확한 사용법
# file_path = os.path.join(r"B:\", "python", "pandas", "pandas_xlsm", file_name)

# 방법 3: 상대 경로 사용 시 (작업 디렉토리 확인 필수)
# print("현재 작업 디렉토리:", os.getcwd())
# file_path = os.path.join("python", "pandas", "pandas_xlsm", file_name)

# 데이터프레임 생성
df_new = pd.DataFrame({"A": ['row3col1', 'row4col1', 'row5col1'], "B": ['row3col2', 'row4col2', 'row5col2']})
updates = {"Sheet3": df_new}

# 실행
update_excel_sheets(file_path, updates, start_row=3, start_col=1, include_header=False)

 

대리점잔액계산.xlsm

import pandas as pd
from openpyxl import load_workbook
from openpyxl.styles import Alignment
import os

def update_excel_sheets(file_path, sheet_updates, output_path=None, start_row=0, start_col=0, include_header=False):
    """숫자 오른쪽 정렬이 적용된 최종 버전"""
    # 절대 경로로 변환
    file_path = os.path.abspath(file_path)
    print(f"실제 접근 경로: {file_path}")
    
    if output_path is None:
        output_path = file_path
    else:
        output_path = os.path.abspath(output_path)
    
    # 확장자 확인
    ext = os.path.splitext(file_path)[1].lower()
    is_xlsm = (ext == '.xlsm')
    
    try:
        # 파일 로드
        book = load_workbook(file_path, keep_vba=is_xlsm)
        existing_sheets = book.sheetnames
        
        with pd.ExcelWriter(
            output_path,
            engine='openpyxl',
            mode='a',
            if_sheet_exists='overlay'
        ) as writer:
            writer._book = book
            writer._sheets = {ws.title: ws for ws in book.worksheets}
            
            for sheet_name, df in sheet_updates.items():
                if sheet_name not in existing_sheets:
                    ws = book.create_sheet(sheet_name)
                    writer._sheets[sheet_name] = ws
                else:
                    ws = book[sheet_name]
                    if start_row > 0 or start_col > 0:
                        for row in ws.iter_rows(min_row=start_row+1, min_col=start_col+1):
                            for cell in row:
                                cell.value = None
                
                # 데이터 쓰기
                df.to_excel(
                    writer,
                    sheet_name=sheet_name,
                    index=False,
                    startrow=start_row,
                    startcol=start_col,
                    header=include_header
                )
                
                # 스타일 적용
                ws = writer.sheets[sheet_name]
                # right_align = Alignment(horizontal='right')
                
                # 숫자 컬럼 오른쪽 정렬
                # numeric_cols = ['입금예정액', '입금액', '잔액']
                # for col_name in numeric_cols:
                #     if col_name in df.columns:
                #         col_idx = df.columns.get_loc(col_name) + 1  # 1-based index
                #         for row in range(start_row + 1, start_row + len(df) + 1):
                #             ws.cell(row=row, column=col_idx).alignment = right_align
                
                # 날짜 형식 및 정렬
                date_cols = ['기간마침', '실제입금일']
                for col_name in date_cols:
                    if col_name in df.columns:
                        col_idx = df.columns.get_loc(col_name) + 1
                        for row in range(start_row + 1, start_row + len(df) + 1):
                            cell = ws.cell(row=row, column=col_idx)
                            cell.number_format = 'yyyy-mm-dd'
                            # cell.alignment = right_align
        
        print(f"파일 저장 완료: {output_path}")
    
    except FileNotFoundError:
        print(f"⚠️ 오류: 파일을 찾을 수 없습니다. 경로를 확인하세요.\n{file_path}")
    except Exception as e:
        print(f"⚠️ 예상치 못한 오류: {str(e)}")

# 사용 예시
file_path = "대리점잔액계산.xlsm"
sheet_name = "대리점입금관리"

try:
    # 데이터 읽기
    df = pd.read_excel(file_path, sheet_name=sheet_name)
    
    # 데이터 전처리
    df['입금예정액'] = df['입금예정액'].fillna(0).astype('int')
    df['입금액'] = df['입금액'].fillna(0).astype('int')
    df['잔액'] = df.groupby('지점')['입금예정액'].cumsum() - df.groupby('지점')['입금액'].cumsum()
    
    # 날짜 처리
    df['기간마침'] = pd.to_datetime(df['기간마침'], errors='coerce')
    df['실제입금일'] = pd.to_datetime(df['실제입금일'], errors='coerce').fillna(pd.Timestamp('1900-01-01'))
    
    # 숫자 포맷 (콤마 표시)
    # for col in ['입금예정액', '입금액', '잔액']:
    #     df[col] = df[col].apply(lambda x: f"{x:,}")
    
    # 함수 실행
    update_excel_sheets(
        file_path=file_path,
        sheet_updates={sheet_name: df},
        start_row=1,
        start_col=0,
        include_header=False
    )

except FileNotFoundError:
    print(f"파일을 찾을 수 없습니다: {file_path}")
except Exception as e:
    print(f"오류 발생: {str(e)}")