Search

Python 21. 파이썬으로 엑셀 다루기 - 기본편 (feat. openpyxl)

Created at
2024/01/26
Updated at
2025/01/16
Tags
Keywords
업무자동화
3 more properties
#python #파이썬 #업무자동화 #openpyxl
엑셀은 많은 직장인의 필수 프로그램 중 하나다. python으로 엑셀 작업을 자동화할 수 있다면 반복적이고 많은 양의 작업도 빠르고 정확하게 처리할 수 있다. 데이터 분석가 입장에서도 현업 부서에서 엑셀 결과물이 필요한 경우 유용하게 활용할 수 있는 부분이다.
대표적인 라이브러리로는 openpyxl 패키지가 있는데, 이번 포스팅에서 우선 기본적인 기능에 대한 내용 - 엑셀 파일을 읽고, 데이터를 불러오거나 내보내는 - 을 정리해본다. 서식 지정 등의 추가적인 내용은 또 다른 포스팅에서 정리를 이어가는 것으로.
늘 그렇듯 가장 정확한 최신의 내용은 공식문서에서 확인할 수 있다. OpenPyXL 공식 document는 아래의 링크를 참고하자.
목차

1. 기본 이용 방법

1.1 openpyxl 패키지 설치 및 불러오기

패키지 설치
터미널 창에서 아래의 명령어로 openpyxl 패키지를 설치할 수 있다.
$ pip install openpyxl
Shell
복사
아나콘다 사용자의 경우 이미 설치되어 있으므로 다음 단계로 넘어가자.
패키지 불러오기
이제 파이썬 스크립트 파일에서 아래와 같이 패키지를 불러온다. alias로는 op를 활용해보자.
import openpyxl as op
Python
복사

1.2 Workbook & Worksheet 개념

우리가 엑셀 프로그램으로 열어보는 하나의 엑셀 파일(.xlsx)은 하나의 workbook이며, 하나의 workbook을 구성하는 각 시트를 worksheet 라고 한다.
행과 열로 이루어진 셀(cell)들이 하나의 worksheet를 구성한다.
프로그래밍적으로 엑셀을 다루기 위해서는 workbook(파일)에 접근하고 → 그 중 원하는 worksheet(시트, 탭)에 접근하고 → 해당 worksheet에서 원하는 cell에 접근해서 특정 작업을 한다고 생각하면 된다.

1.3 Workbook과 엑셀 파일 다루기

workbook 생성하기
통상 wb라는 이름으로 Workbook() 클래스의 인스턴스를 생성한다.
처음 workbook을 생성하면 default로 Sheet가 하나 만들어진다.
from openpyxl import Workbook # workbook 생성 wb = Workbook()
Python
복사
엑셀 파일에서 workbook 불러오기
wb = op.load_workbook(filename = "{file_name}.xlsx")
Python
복사
엑셀 파일로 저장하기
생성하거나 수정한 workbook은 save 메서드로 엑셀 파일로 저장해야 반영이 되고, 엑셀 프로그램을 열어 확인할 수 있다.
wb.save("{filename}.xlsx")
Python
복사

1.4 Worksheet 다루기

1) 시트에 접근(선택)하기

첫 시트(활성화된 시트)에 접근하기
sh = wb.active
Python
복사
workbook의 worksheet 리스트 확인하기
wb.sheetnames # wb.get_sheet_names() # deprecated
Python
복사
test_excel.xlsx 로 만든 파일의 기본 시트명인 Sheet를 확인할 수 있다.
특정 시트 접근하기
sh = wb["{sheet_name}"] # sh = wb.get_sheet_by_name("{sheet_name}") # deprecated
Python
복사

2) 새로운 시트 만들기 & 삭제하기

새로운 worksheet를 추가하려면 create_sheet() 메서드를 사용한다. 시트의 위치는 기본적으로 맨 마지막에, 시트의 이름은 Sheet{n}으로 생성된다.
sh_new = wb.create_sheet()
Python
복사
시트의 이름이나 위치를 지정하여 생성할 수도 있다. worksheet의 위치 index는 0부터 시작한다
sh_new = wb.create_sheet("sheet_name", 1)
Python
복사
시트 삭제하기
wb.remove(sh_new)
Python
복사
sh_new로 생성했던 시트 ‘Sheet1’이 삭제되었다.

3) 시트의 속성 지정하기

시트 이름 지정하기
sh.title = "sheet_name"
Python
복사
시트 탭 색상 지정하기
sh.sheet_properties.tabColor = "{hex_code}"
Python
복사
시트의 이름과 탭 색상이 지정되었다.

1.4 Cell 다루기

1) Basic

셀 객체: 특정 셀을 객체로 받기. 아래의 두 가지 방법 중 하나로 인덱싱
a = sh.cell(row=1, column=2) # cell 속성 사용 a = sh["B1"] # 시트의 인덱스 사용
Python
복사
셀의 여러가지 속성
# cell 객체 a에 대해 다양한 속성을 확인 a.value # 저장된 데이터 값 a.row # 행 (숫자값, 1부터 시작) a.column # 열 (숫자값, 1부터 시작) a.coordinate # 좌표 (셀주소. ex: 'B1')
Python
복사
셀에 데이터 입력하기
# cell 객체 a의 value 속성에 10을 할당 a.value = 10 # cell의 데이터를 지우려면 ""(공백)을 입력 a.value = ""
Python
복사
B1 셀에 10을 입력했다.

2) 특정 범위의 셀에 접근

셀주소 사용
rng = sh["A1":"C3"] # 범위 저장 -> 2차원 튜플 for row in rng: # 튜플의 첫번째 차원: 행 (범위 내의 각 행) for cell in row: # 튜플의 두번째 차원: 열 (행 내의 각 셀) print(cell.value)
Python
복사
엑셀 파일에 스크린샷처럼 값을 입력하고 저장한 뒤 그 내용을 읽어왔다.
.rows, .colomns: 시트에서 데이터가 입력된 범위의 row, column을 반환하는 iterator
# 시트의 각 row의 셀 객체 튜플 출력 for row in sh.rows: print(row)
Python
복사
(<Cell '첫시트'.A1>, <Cell '첫시트'.B1>, <Cell '첫시트'.C1>) (<Cell '첫시트'.A2>, <Cell '첫시트'.B2>, <Cell '첫시트'.C2>) (<Cell '첫시트'.A3>, <Cell '첫시트'.B3>, <Cell '첫시트'.C3>)
# 시트의 각 column의 셀 객체 튜플 출력 for col in sh.columns: print(col)
Python
복사
(<Cell '첫시트'.A1>, <Cell '첫시트'.A2>, <Cell '첫시트'.A3>) (<Cell '첫시트'.B1>, <Cell '첫시트'.B2>, <Cell '첫시트'.B3>) (<Cell '첫시트'.C1>, <Cell '첫시트'.C2>, <Cell '첫시트'.C3>)
.max_row, .max_column: 시트에서 데이터가 입력된 최대 행, 열의 값을 정수로 반환
sh.max_row sh.max_column
Python
복사
iter_rows()iter_cols()를 이용
iter_rows(), iter_cols()를 선언하면 generator가 생성
생성된 generator를 이용하여 row와 col의 범위(min - max)에 순서대로 접근
# 지정한 범위의 셀에서 셀 주소를 리스트로 받아오기 ls = [] for row in sh.iter_rows(min_row=1, max_row=10, min_col=2, max_col=5): a = [] for cell in row: a.append(cell.coordinate) ls.append(a) ls
Python
복사
>>> [['B1', 'C1', 'D1', 'E1'], ['B2', 'C2', 'D2', 'E2'], ['B3', 'C3', 'D3', 'E3'], ['B4', 'C4', 'D4', 'E4'], ['B5', 'C5', 'D5', 'E5'], ['B6', 'C6', 'D6', 'E6'], ['B7', 'C7', 'D7', 'E7'], ['B8', 'C8', 'D8', 'E8'], ['B9', 'C9', 'D9', 'E9'], ['B10', 'C10', 'D10', 'E10']]
행 삭제, 열 삭제 (데이터 삭제가 아닌 행, 열 자체를 제거함)
sh.delete_rows(1, 2) # 1행부터 2개 행을 삭제 sh.delete_cols(2, 1) # 2열(B열)부터 1개 열을 삭제
Python
복사

2. DataFrame 엑셀

데이터 관련 업무에서 python으로 엑셀을 잘 다루는데 있어 핵심은 결국 pandas의 dataframe으로 만들어진 테이블 형태의 데이터를 엑셀 파일로 잘 내보내거나, 반대로 엑셀에서 데이터를 읽어와서 dataframe으로 잘 받아오는 데에 있을 것이다.
openpyxl의 경우 구글 시트를 다루는 pygsheet 패키지보다는 dataframe과의 호환성은 좀 떨어지는 것으로 보인다. pygsheet의 경우 간편하게 dataframe을 영역을 지정해서 바로 내보내거나 가져오는 메서드가 있는 반면, openpyxl에서는 반복문 등을 이용해서 데이터를 내보내야 한다.

2.1 DataFrame → 엑셀

1) dataframe_to_rows 활용

모듈을 활용해 가장 간단한 방법이지만, 시트에서 입력할 셀의 영역을 지정할 수 없다.
시트상 마지막 row 다음부터 행 방향으로 dataframe이 한 줄씩 append된다.
from openpyxl.utils.dataframe import dataframe_to_rows for r in dataframe_to_rows(df, index=True, header=True): sh.append(r)
Python
복사
index와 header를 True로 넣어주어서 컬럼명과 인덱스명이 함께 입력되었다.

2) 데이터를 입력할 셀 영역을 지정할 수 있는 방법

iter_rows() 이용
min_row = 10 # 데이터 입력을 시작할 row index max_row = min_row + len(df) - 1 min_col = 3 # 데이터 입력을 시작할 column index max_col = min_col + len(df.columns.tolist()) - 1 i = 0 for row in sh.iter_rows(min_row=min_row, max_row=max_row, min_col=min_col, max_col=max_col): j = 0 for cell in row: cell.value = df.iloc[i, j] j += 1 i += 1
Python
복사
C10부터 시작하는 4*3 데이터가 입력되었다.
행, 열 index를 for문에 직접 활용
시트와 DataFrame의 행, 열 index를 활용하면 이중 for문을 사용하지 않아도 된다.
idx = [(i, j) for i in range(len(df)) for j in range(len(df.columns.tolist()))] min_row = 14 # 데이터 입력을 시작할 row index min_col = 2 # 데이터 입력을 시작할 column index for (i, j) in idx: cell = sh.cell(row=i+min_row, column=j+min_col) # 셀 데이터 입력 cell.value = df.iloc[i, j]
Python
복사
B14부터 데이터가 입력되었다.

2.2 엑셀 → DataFrame

1) 전체 데이터를 dataframe으로 받아오기

# 워크시트의 전체 데이터를 dataframe으로 받아온다 df = pd.DataFrame(sh.values)
Python
복사
# 데이터에 header가 포함된 경우, 첫줄을 header로 지정할 수 있다. df = df.rename(columns=df.iloc[0]) df = df.iloc[1:].reset_index(drop=True)
Python
복사

2) 특정 영역의 데이터를 dataframe으로 받아오기

이제 엑셀에 영역을 지정해 아래와 같이 내보냈던 데이터를 거꾸로 받아와보자.
iter_rows() 이용
min_row = 10 # 데이터를 가져올 시작 위치 row index rows = 3 # 가져올 행 수 max_row = min_row + rows - 1 min_col = 3 # 데이터를 가져올 시작 위치 column index cols = 4 # 가져올 열 수 max_col = min_col + cols - 1 df = pd.DataFrame() # 빈 DataFrame 생성 i = 0 for row in sh.iter_rows(min_row=min_row, max_row=max_row, min_col=min_col, max_col=max_col): j = 0 for cell in row: df.loc[i, j] = cell.value # 셀에 데이터 입력 j += 1 i += 1
Python
복사
가져온 결과 데이터
행, 열 index를 for문에 직접 활용
시트와 DataFrame의 행, 열 index를 활용하면 이중 for문을 사용하지 않아도 된다.
min_row = 14 # 데이터를 가져올 시작 위치 row index rows = 3 # 가져올 행 수 min_col = 2 # 데이터를 가져올 시작 위치 column index cols = 4 # 가져올 열 수 idx = [(i, j) for i in range(rows) for j in range(cols)] df = pd.DataFrame() # 빈 DataFrame 생성 for (i, j) in idx: # 셀 접근 cell = sh.cell(row=i+min_row, column=j+min_col) # 셀 데이터 df로 가져오기 df.loc[i, j] = cell.value
Python
복사
가져온 결과 데이터
이상, python으로 엑셀 파일을 다루는 기본적인 방법에 대해 알아보았다.
위에서 얘기한 것처럼 엑셀 서식 지정 등 추가적인 내용은 추후 또 다른 포스팅으로 정리를 해보기로 하자.