SAP에서 다운로드 받은 파일: xls 에서 xlsx 로 자동 변환하기

Yubin's velog ! ·2023년 7월 24일
1
post-thumbnail

background

SAP을 사용한다면 가장 많이 마주하는 파일 형식은 아마 .xls 엑셀 형식일 것이다.

xlsx 형식을 주로 쓰기에 매번 파일 포맷 (xls -> xlsx) 을 바꾸는게 단순하지만 너무 귀찮은 작업이었다. 특히 적은 양의 파일이면 처리할 수 있겠지만, 매번 많은 양의 파일을 작업할 때는 다른 이야기가 되기에 이를 자동으로 변환할 수 있는 부분이 있었으면 했다.

struggle point !

Excel 어플리케이션은 업무와 뗄레야 뗄 수 없는 필수 프로그램이기에 해당 작업과 관련된 유명한 라이브러리들 이미 많았고, 또 기존에 엑셀 작업을 파이썬에서 많이 사용하였기에 이와 비슷한 로직으로 접근하면 될 것으로 생각했다.

그러나 예상외로 SAP 에서 다운받은 파일이여서(?) 그런지 일반적으로 엑셀 작업을 할 때 많이 사용하는openpyxl, xlrd, pyexcel 으로 원하는 결과값을 얻을 수 없었다. 변환이 되더라도 빈 알맹이만 .. 있는 파일이 나오기 일쑤였다. 사실 이 정도면 자동화보다 manually 변환하는게 낫지 않을까라는 생각이 찰나 드는 순간 pywin32 라이브러리의 win32com.client 모듈을 사용하는 방법을 발견하였다 !

Hurraaaay 🤸‍


solution

summary
a. xls 파일 input 받아오기 via tkinter
b. for 구문 돌려서 (a)에서 받은 input : xls를 xlsx 로 변환하기 via win32com.client

지금 변환해야 하는 파일이 10개가 있다고 치자.

파일을 불러오는 방법은 크게 두가지로 나눌 수 있다.

  • input X : 주어진 파일 경로(fixed)에서 데이터들을 불러오는 경우
    * (ex) os.listdir() & endswith('.XLS') 조합 사용

  • input O : 파일 경로를 input으로 받아 접근하는 방법
    * (ex) tkinter

나같은 경우는 파일 경로가 달라지는 경우가 종종 있어서, tkinter 을 사용하여 파일 브라우저 창이 뜨는 방법을 택하였다.


# tkinter 로 파일 경로 input을 direct로 받기 / able to read multiple files! 

import tkinter as tk
from tkinter import filedialog as fd
from tkinter import messagebox as mb

root = tk.Tk()

files = fd.askopenfilenames(parent = root, title = "변환하고자 하는 xls 파일을 선택해주세요.", filetypes = [("Excel files","*xls“)])

if file == "" : 
	mb.showarnning("Warning", "XLS 파일 선택해주세요.")
    
root.destroy() 


tkinter을 사용하면, 위와 같이 편하고 익숙한 방법으로 파일들을 불러올 수 있다. 여기서는 filetypes 을 xls 로만 설정하였기에 해당 확장자만 가진 파일만 보여주고 있다. 내가 변환하고자 하는 XLS 파일들만 선택/드래그 해주면 파일 선택은 끝 !


(특히 나같은 경우는 해당 자동화를 부서내에서 공유하는 경우가 많기에, UI Friendly 가 매우 중요하다. 컴퓨터? 도스창 같은 느낌이 물씬 나면 사용하기를 어려워하시거나 거리감을 느끼시기에 ㅎㅎ 나도 마찬가지이다 ..! 내가 tkinter를 좋아하는 이유이다 ㅎㅎ)

그리고 받아온 xls 파일들은 tuple 형식으로 데이터가 저장이 된다. 인덱싱을 이용해서 한다면 문자열만 그대로 가져올 수 있기에 okay!

(ex) files = ("./a.XLS", "./b.XLS", "./c.XLS", "./d.XLS", "./e.XLS", "./f.XLS", "./g.XLS", "./h.XLS", "./i.XLS", "./j.XLS")


그리고 나서 다음 step은 files 리스트 안에 있는 값들을 for 구문 돌려서 하나씩 xlsx 로 변환하는 방법을 사용하려 한다.

xlsx_fullname_list = []

for i in range(len(files)): 
    file_name = files[i].split("/")[-1] # 파일명만 따로 빼내고 싶어서 지정 
    excel = win32.gencache.EnsureDispatch('Excel.Application')
    
    try:
        wb = excel.Workbooks.Open(files[i])
        wb.SaveAs(files[i] + "X", FileFormat = 51)
        wb.Close()
        print("File Well Created!")
    
    except: 
        print("Error Occurred!") # 파일이 열려있거나 하면 에러등이 발생하기에 
        
            
excel.Application.Quit()
    

기존 파일인 XLS 파일을 삭제하려고 하였지만, data maintenance 취지에서 (혹시 몰라 변환하는 과정에서 데이터가 왜곡되어 파일이 망가질까봐 원본과 비교하는 의미에서) 남겨두었다 ! 😎


breakdown !

a) tkinter

import tkinter as tk # tkinter = GUI toolkit for python
from tkinter as filedialog as fd
from tkinter as messagebox as mb

root = tk.Tk()

files = fd.askopenfilenames(parent = root, title = "변환하고자 하는 xls 파일을 선택해주세요.", filetypes = [("Excel files","*xls)])

if file == "" : 
	mb.showarnning("Warning", "XLS 파일 선택해주세요.")
    
root.destroy() 

  • tk.Tk = tinkter.Tk() : construction function, to create the main application window. 여기서는 root 이라고 지정
    - Tk 클래스의 인스턴스 = main application window (= usually the top level of window)

  • fd = filedialog : provides function to display various types of files dialogs (ex) opening/saving/choosing directories

  • askopenfilenames() : specific function from filedialog module , used to open a file dialog that allows the user to select one or more files, return values as tuple data type

  • parent = root : parent parameter is optional / allows user to specifiy the parent window for the file dialog
    - 여기서 해당 부분은 무슨 역할을 하는지 보면, making main application window (여기서는 root)를 parent of the file dialog로 설정
    • 위와 같은 parent-child relationship을 사용하면 좋은 점은 layer를 설정 가능(즉, priority)
    • enables user experiening smooth interaction between various windows in the application
    • common practice when displaying file dialogs or other secondary dialogs in Tkinter application
  • root.destroy() : closes the main application window
    - 해당 부분을 설정하지 않으면, 하기와 같이 창이 계속 떠있는다 (신경이 꽤나 쓰인다 ..)

b) xls -> xlsx 변환


files = "./a.XLS"
 
import win32com.client as win32

excel = win32.gencache.EnsureDispatch('Excel.Application')

wb = excel.Workbooks.Open(files)
wb.SaveAs(files + "X", FileFormat = 51) # xlsx format = 51 / xls format = 56
wb.Close()

  • pywin32 라이브러리의 win32com.client 모듈 사용

  • win32.gencache.EnsureDispatch('Excel.Application') : allows to automate action within Excel apllicaton by creating an instance of Microsoft Excel application by using EnsureDispatch method from win32com.Client.gencache

  • wb = excel.Workbooks.open(files) : Workbooks property is used to access the collection of workbook / open method is called to open specified workbook

  • FileFormat = 51 : file format identifier for xlsx is 51 whereas xls is 56
    - XLS (Excel Binary Format)= 56
    - XLSX (Excel Open XML Format) = 51

2개의 댓글

comment-user-thumbnail
2023년 7월 24일

유익한글이네용👍👍👍

1개의 답글