엑셀 자동화

출처: https://www.youtube.com/watch?v=exgO1LFl9x8

파일 만들기

  • openpyxl 설치
    파이썬에서 엑셀을 다루기 위한 도구인 openpyxl을 설치한다.
pip install openpyxl
from openpyxl import Workbook

wb = Workbook() # 새 워크북 생성
ws = wb.active # 현재 활성화된 sheet 가져옴

ws.title = "JuSheet" # sheet의 이름 변경

wb.save("sample.xlsx")
wb.close()

시트

from openpyxl import Workbook
wb = Workbook()

# wb.active
ws = wb.create_sheet() # 새로운 Sheet 기본 이름으로 생성
ws.title = "MySheet" # Sheet 이름 변경
ws.sheet_properties.tabColor = "ff66ff" # RGB 탭 색상 변경

# Sheet, MySheet, YourSheet
ws1 = wb.create_sheet("YourSheet") # 주어진 이름으로 sheet 생성
ws2 = wb.create_sheet("NewSheet", 2) # 2번째 index에 Sheet 생성

new_ws = wb["NewSheet"] # Dict 형태로 Sheet 접근

# Sheet 복사
new_ws["A1"] = "Test"
target = wb.copy_worksheet(new_ws)
target.title = "Copied Sheet"

print(wb.sheetnames) # 모든 Sheet 이름 확인

wb.save("sample.xlsx")

셀 기본

from openpyxl import Workbook
wb = Workbook()

ws = wb.active
ws.title = "JuSheet"

# 셀에 값 입력
ws["A1"] = 1
ws["A2"] = 2
ws["A3"] = 3

ws["B4"] = 4
ws["B5"] = 5
ws["B6"] = 6

print(ws["A1"]) # A1 셀의 정보
print(ws["A1"].value) # A1 '값' 
print(ws["A10"].value) # 값이 없을 땐 'None' 출력

# row = 1, 2, 3, ...
# column = A(1), B(2), C(3), ...
print(ws.cell(row=1, column=1).value) # ws["A1"].value
print(ws.cell(row=1, column=2).value) # ws["B1"].value

c = ws.cell(row=1, column=3, value=10) # ws["C1"].value = 10
print(c.value) # ws["C1"]


from random import *

index = 1
# 반복문을 이용해서 랜덤 숫자 채우기
for x in range(1, 11): # 10개 row
    for y in range(1, 11): # 10개 column
        # ws.cell(row=x, column=y, value=randint(0, 100))
        ws.cell(row=x, column=y, value=index)
        index += 1

wb.save("sample.xlsx")

파일 열기

from openpyxl import load_workbook # 파일 불러오기
wb = load_workbook("sample.xlsx") # sample.xlsx 파일에서 wb 불러옴
ws = wb.active # 활성화된 Sheet

# cell 데이터 불러오기
for x in range(1, 11):
    for y in range(1, 11):
        print(ws.cell(row=x, column=y).value, end=" ") # 1 2 3 4 ..
    print()

# cell 갯수를 모를 때
for x in range(1, ws.max_row + 1):
    for y in range(1, ws.max_column + 1):
        print(ws.cell(row=x, column=y).value, end=" ") # 1 2 3 4 ..
    print()

셀 영역

# 셀을 하나씩 가져오는 것이 아닌 범위를 지정해서 가져오기
from openpyxl import Workbook
from random import *

wb = Workbook()
ws = wb.active

# 1줄씩 데이터 넣기
ws.append(["번호", "영어", "수학"])
for i in range(1, 11):
    ws.append([i, randint(0, 100), randint(0,100)])

# 영어 점수만 가져오기
col_B = ws["B"]
for cell in col_B:
    print(cell.value)

# 영어, 수학 점수 가져오기
col_range = ws["B:C"]
for cols in col_range:
    for cell in cols:
        print(cell.value)

# 1번째 row만 가져오기
row_title = ws[1]
for cell in row_title:
    print(cell.value)

# 2번째 줄에서 6번째 줄까지 가져오기
row_range = ws[2:6] 
for rows in row_range:
    for cell in rows:
        print(cell.value, end=" ")
    print() # 줄바꿈

from openpyxl.utils.cell import coordinate_from_string

row_range = ws[2:ws.max_row] # 2번째 줄부터 막줄까지
for rows in row_range:
    for cell in rows:
        # print(cell.value, end=" ")
        # print(cell.coordinate, end=" ") # 셀의 좌표 정보 (A2, B2, C2, ...)
        xy = coordinate_from_string(cell.coordinate)
        print(xy, end=" ")
    print() # 줄바꿈



wb.save("sample.xlsx")

# 전체 rows
print(tuple(ws.rows)) # 한 줄씩 가져와서 튜플로

# 전체 columns
print(tuple(ws.columns)) # 한 열씩 가져와서 튜플로

for row in tuple(ws.rows):
    print(row[1].value)

for column in tuple(ws.columns):
    print(column[0].value)

for row in ws.iter_rows(): # 전체 row
    print(row[2].value)

for column in ws.iter_cols(): # 전체 column
    print(column[1].value)

# 범위 지정도 가능
# 1번째 줄 ~ 5번째 줄, 2번째 열 ~ 3번째 열
for row in ws.iter_rows(min_row=1, max_row=5, min_col=2, max_col=3):
    print(row[0].value, row[1].value) # 수학, 영어
    print(row)

찾기

  • 찾아서 바꿔주기
from openpyxl import load_workbook
wb = load_workbook("sample.xlsx")
ws = wb.active

for row in ws.iter_rows(min_row=2): # 제목 스킵
    # 번호, 영어, 수학
    if int(row[1].value) > 80:
        print(row[0].value, "번 학생은 영어 천재")

for row in ws.iter_rows(max_row=1): # 첫번째 줄에서만
    for cell in row:
        if cell.value == "영어":
            cell.value = "컴퓨터"

wb.save("sample_modified.xlsx")

삽입

from openpyxl import load_workbook

wb = load_workbook("sample.xlsx")
ws = wb.active

ws.insert_rows(8) # 8번째 줄이 비워짐
ws.insert_rows(8, 5) # 8번째 줄부터 5줄이 비워짐

ws.insert_cols(2) # B번째 열이 비워짐

wb.save("sample_inser.xlsx")

삭제

from openpyxl import load_workbook

wb = load_workbook("sample.xlsx")
ws = wb.active

ws.delete_rows(8, 3)  # 8번째 줄에 있는 7번 학생 데이터 삭제
ws.delete_cols(2, 2)

wb.save("sample_delete.xlsx")

이동

from openpyxl import load_workbook

wb = load_workbook("sample.xlsx")
ws = wb.active

# 번호 영어 수학
# 번호 (국어) 영어 수학

ws.move_range("B1:C11", rows=0, cols=1)  # 오른쪽으로 한 열 이동
ws["B1"].value = "국어"

wb.save("sample_move.xlsx")

차트

from openpyxl.chart import BarChart, Reference, LineChart
from openpyxl import load_workbook

wb = load_workbook("sample.xlsx")
ws = wb.active

bar_value = Reference(ws, min_row=1, max_row=11,
                      min_col=2, max_col=3)  # B1:C11
bar_chart = BarChart()  # 차트 종류 설정 (Bar, Line, pie)
bar_chart.add_data(bar_value)  # 차트 데이터 추가
ws.add_chart(bar_chart, "E1")  # 차트 넣을 위치 정의

line_value = Reference(ws, min_row=1, max_row=11,
                       min_col=2, max_col=3)  # B1:C11
line_chart = LineChart()
line_chart.add_data(line_value, titles_from_data=True)  # 계열 > 영어, 수학
line_chart.title = "성적표"
line_chart.style = 20  # 미리 정의된 스타일 적용
line_chart.y_axis.title = "점수"  # y축 제목
line_chart.x_axis.title = "번호"  # x축 제목
ws.add_chart(line_chart, "E14")

wb.save("sample_chart.xlsx")

셀 스타일

from openpyxl import load_workbook
from openpyxl.styles import Font, Border, Side

wb = load_workbook("sample.xlsx")
ws = wb.active

# 번호, 영어, 수학
a1 = ws["A1"]  # 번호
b1 = ws["B1"]  # 영어
c1 = ws["C1"]  # 수학

# A 열의 너비를 5로 설정
ws.column_dimensions["A"].width = 5

# 1 행의 높이를 50으로 설정
ws.row_dimensions[1].height = 50

# 스타일 적용
a1.font = Font(color="FF0000", italic=True, bold=True)  # 글자 색은 빨갛게, 이텔릭, 굵게
b1.font = Font(color="BB33FF", name="Arial", strike=True)  # 폰트 Arial, 취소선
c1.font = Font(color="0000FF", size=20, underline="single")  # 글자 크기 20, 밑줄 적용

# 테두리 적용
thin_border = Border(left=Side(style="thin"), right=Side(style="thin"),
                     top=Side(style="thin"), bottom=Side(style="thin"))
a1.border = thin_border
b1.border = thin_border
c1.border = thin_border

wb.save("sample_style.xlsx")

# 40점 넘는 셀에 대해 초록색 적용
for row in ws.rows:
    for cell in row:
        # 각 cell에 대해 정렬
        cell.alignment = Alignment(horizontal="center", vertical="center")
        if cell.column == 1:  # A 번호열은 제외
            continue
        # cell이 정수형 데이터이고 40점보다 높으면
        if isinstance(cell.value, int) and cell.value > 40:
            cell.fill = PatternFill(
                fgColor="00FF00", fill_type="solid")  # 배경을 초록색으로
            cell.font = Font(color="FF0000")  # 폰트 색상 변경

# 틀 고정
ws.freeze_panes = "B2"  # B2 기준으로 틀 고정

수식

from openpyxl import Workbook
import datetime

wb = Workbook()
ws = wb.active

ws["A1"] = datetime.datetime.today()  # 오늘 날짜 정보
ws["A2"] = "=SUM(1, 2, 3)"  # 1 + 2 + 3 = 6 (합계)
ws["A3"] = "=AVERAGE(1, 2, 3)"  # 2 (평균)

ws["A4"] = 10
ws["A5"] = 20
ws["A6"] = "=SUM(A4:A5)"  # 30

wb.save("smaple_formula.xlsx")

수식 (데이터 전용)

from openpyxl import load_workbook

# wb = load_workbook("sample_formula.xlsx")
# ws = wb.active

# # 수식 그대로 가져옴
# for row in ws.values:
#     for cell in row:
#         print(Cell)

wb = load_workbook("sample_formula.xlsx", data_only=True)
ws = wb.active

# 수식 계산된 결과
# elvaluate 되지 않은 상태의 데이터는 None
# 엑셀 파일 저장 후에는 계산 값 나옴
for row in ws.values:
    for cell in row:
        print(cell)

셀 병합

from openpyxl import Workbook

wb = Workbook()
ws = wb.active

# 병합하기
ws.merge_cells("B2:D2")  # B2 부터 D2 까지 병합
ws["B2"].value = "Merged Cell"

wb.save("sample_merge.xlsx")
  • 병합 해제
from openpyxl import load_workbook

wb = load_workbook("sample_merge.xlsx")
ws = wb.active

# B2:D2 병합되어 있던 셀 해제
ws.unmerge_cells("B2:D2")

wb.save("sample_unmerge.xlsx")

이미지 삽입

from openpyxl import Workbook
from openpyxl.drawing.image import Image

wb = Workbook()
ws = wb.active

img = Image("img1.png")

# C3 위치에 img1.png 파일 이미지 삽입
ws.add_image(img, "C3")

wb.save("sample_image.xlsx")

퀴즈

Quiz)

  • 출석 10
  • 퀴즈1 10
  • 퀴즈2 10
  • 중간고사 20
  • 기말고사 30
  • 프로젝트 20

  • 총합 100


    퀴즈 2 문제에 오류를 발견하여 모두 만점 처리를 하기로 하였다.
    현재까지 작성된 최종 성적 데이터를 기준으로 아래와 같이 수정하라.

  1. 퀴즈2 점수를 10으로 수정
  2. H열에 총점(SUM 이용), I열에 성적 정보 추가
  • 총전 90점 이상 A, 80 이상 B, 70 이상 C, 나머지 D
  1. 출석이 5 미만인 학생은 총점 상관없이 F

  • 최종 파일명 : scores.xlsx

[현재까지 작성된 최종 성적 데이터]
학번, 출석, 퀴즈1, 퀴즈2, 중간고사, 기말고사, 프로젝트
1,10,8,5,14,26,12
2,7,3,7,15,24,18
3,9,5,8,8,12,4
4,7,8,7,17,21,18
5,7,8,7,16,25,15
6,3,5,8,8,17,0
7,4,9,10,16,27,18
8,6,6,6,15,19,17
9,10,10,9,19,30,19
10,9,8,8,20,25,20

from openpyxl import Workbook

wb = Workbook()
ws = wb.active

# 현재까지 작성된 최종 성적 데이터를 넣기
ws.append(("학번", "출석", "퀴즈1", "퀴즈2", "중간고사", "기말고사", "프로젝트"))
scores = [
    (1, 10, 8, 5, 14, 26, 12),
    (2, 7, 3, 7, 15, 24, 18),
    (3, 9, 5, 8, 8, 12, 4),
    (4, 7, 8, 7, 17, 21, 18),
    (5, 7, 8, 7, 16, 25, 15),
    (6, 3, 5, 8, 8, 17, 0),
    (7, 4, 9, 10, 16, 27, 18),
    (8, 6, 6, 6, 15, 19, 17),
    (9, 10, 10, 9, 19, 30, 19),
    (10, 9, 8, 8, 20, 25, 20)
]

for s in scores:  # 기존 성적 데이터 넣기
    ws.append(s)

for idx, cell in enumerate(ws["D"]):
    if idx == 0:  # 제목인 경우 skip
        continue
    cell.value = 10

ws["H1"] = "총점"
ws["I1"] = "성적"

for idx, score in enumerate(scores, start=2):  # 학번은 skip
    # 총점
    sum_val = sum(score[1:]) - score[3] + 10  # 총점
    ws.cell(row=idx, column=8).value = "=SUM(B{}:G{}".format(idx, idx)
    # 성적
    grade = None  # 성적
    if sum_val >= 90:
        grade = "A"
    elif sum_val >= 80:
        grade = "B"
    elif sum_val >= 70:
        grade = "C"
    else:
        grade = "D"

    if score[1] < 5:
        grade = "F"

    ws.cell(row=idx, column=9).value = grade  # I열에 성적 정보


wb.save("scores.xlsx")

좋은 웹페이지 즐겨찾기