주간 방문객을 엑셀로 변환하는 코드, 정상 추출되지 않음
This commit is contained in:
150
lib/weekly_visitor_forecast_to_excel.py
Normal file
150
lib/weekly_visitor_forecast_to_excel.py
Normal file
@ -0,0 +1,150 @@
|
||||
import pandas as pd
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.styles import Font, Alignment, Border, Side
|
||||
from openpyxl.chart import LineChart, Reference
|
||||
from openpyxl.chart.series import SeriesLabel
|
||||
from datetime import date
|
||||
import os
|
||||
|
||||
|
||||
def generate_excel_report(today, recent_dates, prev_year_dates, recent_data, prev_year_data, filename="visitor_report.xlsx"):
|
||||
weekday_names = ['월', '화', '수', '목', '금', '토', '일']
|
||||
wb = Workbook()
|
||||
ws = wb.active
|
||||
ws.title = "방문자 리포트"
|
||||
|
||||
bold = Font(bold=True)
|
||||
center = Alignment(horizontal='center', vertical='center')
|
||||
thick_border = Border(
|
||||
left=Side(style='thick'), right=Side(style='thick'),
|
||||
top=Side(style='thick'), bottom=Side(style='thick')
|
||||
)
|
||||
|
||||
def fmt(d):
|
||||
return f"{d.month}월 {d.day}일 {weekday_names[d.weekday()]}"
|
||||
|
||||
headers = ["구분"] + [fmt(d) for d in recent_dates]
|
||||
ws.append([])
|
||||
for _ in range(23):
|
||||
ws.append([])
|
||||
|
||||
data_start_row = 24
|
||||
ws.append(headers)
|
||||
|
||||
# 범례 영역
|
||||
ws.merge_cells(start_row=data_start_row, start_column=1, end_row=data_start_row + 6, end_column=1)
|
||||
ws.merge_cells(start_row=data_start_row + 7, start_column=1, end_row=data_start_row + 13, end_column=1)
|
||||
ws.cell(row=data_start_row, column=1, value=f"{today.year}년").font = bold
|
||||
ws.cell(row=data_start_row + 7, column=1, value=f"{today.year - 1}년").font = bold
|
||||
|
||||
def row(label, key, data, suffix="", fmt_func=None):
|
||||
r = [label]
|
||||
for d in recent_dates:
|
||||
v = data.get(d, {}).get(key, "")
|
||||
if fmt_func:
|
||||
v = fmt_func(v)
|
||||
if v == 0 or v == '':
|
||||
r.append("")
|
||||
else:
|
||||
r.append(f"{v}{suffix}")
|
||||
return r
|
||||
|
||||
# 올해 예측 포함 입장객
|
||||
merged_visitors = ["입장객수"]
|
||||
for d in recent_dates:
|
||||
actual = recent_data.get(d, {}).get("입장객 수", 0)
|
||||
forecast = recent_data.get(d, {}).get("예상 방문자", None)
|
||||
if d >= today and forecast:
|
||||
merged_visitors.append(f"{actual} ({int(forecast)})")
|
||||
else:
|
||||
merged_visitors.append(actual if actual else "")
|
||||
|
||||
year_rows = [
|
||||
row("홈페이지", "웹 방문자 수", recent_data),
|
||||
merged_visitors,
|
||||
row("최저기온", "최저기온", recent_data),
|
||||
row("최고기온", "최고기온", recent_data),
|
||||
row("습도", "습도", recent_data, "%"),
|
||||
row("강수량", "강수량", recent_data),
|
||||
row("미세먼지지수", "미세먼지", recent_data),
|
||||
]
|
||||
for r in year_rows:
|
||||
ws.append(r)
|
||||
|
||||
# 작년 데이터
|
||||
def prev_row(label, key, suffix="", fmt_func=None):
|
||||
r = [label]
|
||||
for d in prev_year_dates:
|
||||
v = prev_year_data.get(d, {}).get(key, "")
|
||||
if fmt_func:
|
||||
v = fmt_func(v)
|
||||
if v == 0 or v == '':
|
||||
r.append("")
|
||||
else:
|
||||
r.append(f"{v}{suffix}")
|
||||
return r
|
||||
|
||||
prev_rows = [
|
||||
prev_row("홈페이지", "웹 방문자 수"),
|
||||
prev_row("입장객수", "입장객 수"),
|
||||
prev_row("최저기온", "최저기온"),
|
||||
prev_row("최고기온", "최고기온"),
|
||||
prev_row("습도", "습도", "%"),
|
||||
prev_row("강수량", "강수량"),
|
||||
prev_row("미세먼지지수", "미세먼지"),
|
||||
]
|
||||
for r in prev_rows:
|
||||
ws.append(r)
|
||||
|
||||
# 증감 비교
|
||||
diff = ["입장객 증감"]
|
||||
rate = ["입장객 변동률"]
|
||||
temp_dev = ["최고기온 편차"]
|
||||
|
||||
for i, d in enumerate(recent_dates):
|
||||
cur = recent_data.get(d, {}).get("입장객 수", 0)
|
||||
prev = prev_year_data.get(prev_year_dates[i], {}).get("입장객 수", 0)
|
||||
|
||||
if prev:
|
||||
diff.append(cur - prev)
|
||||
rate.append(f"{(cur - prev) / prev * 100:.1f}%")
|
||||
else:
|
||||
diff.append("")
|
||||
rate.append("")
|
||||
|
||||
t1 = recent_data.get(d, {}).get("최고기온")
|
||||
t2 = prev_year_data.get(prev_year_dates[i], {}).get("최고기온")
|
||||
temp_dev.append(round(t1 - t2, 1) if t1 is not None and t2 is not None else "")
|
||||
|
||||
for row in [diff, rate, temp_dev]:
|
||||
ws.append(row)
|
||||
|
||||
# 굵은 테두리 처리
|
||||
for col, d in enumerate(recent_dates, start=2):
|
||||
if d >= today:
|
||||
for r in range(data_start_row + 1, data_start_row + 18):
|
||||
ws.cell(row=r, column=col).border = thick_border
|
||||
|
||||
# 차트
|
||||
chart = LineChart()
|
||||
chart.title = "입장객 비교 (예상 포함 vs 작년)"
|
||||
chart.height = 10
|
||||
chart.width = 22
|
||||
chart.y_axis.title = "명"
|
||||
chart.x_axis.title = "날짜"
|
||||
|
||||
label_ref = Reference(ws, min_col=2, min_row=data_start_row, max_col=1 + len(recent_dates))
|
||||
this_year_ref = Reference(ws, min_col=2, min_row=data_start_row + 2, max_col=1 + len(recent_dates))
|
||||
last_year_ref = Reference(ws, min_col=2, min_row=data_start_row + 9, max_col=1 + len(recent_dates))
|
||||
|
||||
chart.set_categories(label_ref)
|
||||
chart.add_data(this_year_ref, titles_from_data=False)
|
||||
chart.add_data(last_year_ref, titles_from_data=False)
|
||||
|
||||
chart.series[0].tx = SeriesLabel(v="입장객수 (예상 포함)")
|
||||
chart.series[1].tx = SeriesLabel(v="작년 입장객수")
|
||||
chart.series[1].graphicalProperties.solidFill = "999999"
|
||||
|
||||
ws.add_chart(chart, "A1")
|
||||
wb.save(filename)
|
||||
print(f"✅ 엑셀 저장 완료: {filename}")
|
||||
Reference in New Issue
Block a user