DB_JOB/작업파일/공공기관2/10.한국지역난방공사/_rebuild.py
hehihoho3 b0acd1e705 백업: 셀병합 정상화(D~J)+KDHC 옵션2/행높이17, 오늘(06-21) 제출 17곳 검수·압축
- 공공기관2/3 작업본 + 오늘 제출 17곳 D~J 카테고리 셀병합 정상화
- 한국지역난방공사 옵션2(고아셀 F98 수정)+전행 높이17
- 제출_프리랜서2_2026-06-21.zip 생성(17개 xlsx, 2,468행)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 13:21:26 +09:00

176 lines
6.2 KiB
Python

# -*- coding: utf-8 -*-
import openpyxl, copy, json, io, re
from openpyxl.utils import get_column_letter
from openpyxl.styles import PatternFill
from openpyxl.worksheet.hyperlink import Hyperlink
PATH = '한국지역난방공사.xlsx'
BLUE = PatternFill(fgColor='FFBDD7EE', fill_type='solid')
ORG = '한국지역난방공사'
def menuno(u):
m = re.search(r'menuNo=(\d+)', u or '')
return m.group(1) if m else None
wb = openpyxl.load_workbook(PATH)
ws = wb.active
merges = list(ws.merged_cells.ranges)
def eff(r, c):
v = ws.cell(r, c).value
if v is not None:
return v
for m in merges:
if m.min_row <= r <= m.max_row and m.min_col <= c <= m.max_col:
return ws.cell(m.min_row, m.min_col).value
return None
def mtop(r, c):
for m in merges:
if m.min_row <= r <= m.max_row and m.min_col <= c <= m.max_col:
return (m.min_row, m.min_col)
return (r, c)
DATA0 = ws.max_row
COLS = range(2, 28) # B..AA
orig = []
for r in range(3, DATA0 + 1):
rec = {'path': [eff(r, c) for c in range(4, 11)],
'vals': {c: ws.cell(r, c).value for c in COLS},
'klink': (ws.cell(r, 11).hyperlink.target if ws.cell(r, 11).hyperlink else None),
'styles': {c: copy.copy(ws.cell(*mtop(r, c))._style) for c in COLS},
'rowh': ws.row_dimensions[r].height,
'r0': r, 'new': False, 'newcells': set()}
orig.append(rec)
tmpl = {c: copy.copy(ws.cell(*mtop(3, c))._style) for c in COLS}
def newrec(path, K=None, L=None, M=None, N=None, O='미부착', site=False):
v = {c: None for c in COLS}
v[3] = ORG
if K is not None:
v[11] = K
if site:
v[12] = '사이트'
else:
v[12] = L; v[13] = M; v[14] = N; v[15] = O
return {'path': list(path) + [None] * (7 - len(path)), 'vals': v, 'klink': K,
'styles': None, 'rowh': None, 'new': True, 'newcells': set()}
plan = json.load(io.open('_plan.json', encoding='utf-8'))
g7M = json.load(io.open('_g7M.json', encoding='utf-8'))
OV = {
'200106': ('페이지', 1, '어문'),
'200276': ('페이지', 1, '어문'),
'200091': ('페이지', 1, '어문'),
'200127': ('게시판', 0, '어문,이미지'),
'200427': ('게시판', 0, '어문,이미지'),
}
plan_by_anchor = {p.get('anchor_row'): p for p in plan if 'anchor_row' in p}
g7 = [p for p in plan if p['type'] == 'categoryboard'][0]
OUT = []
for rec in orig:
p = plan_by_anchor.get(rec['r0'])
if rec['r0'] == 11:
cats = g7['tabs']
url0 = "https://www.kdhc.co.kr/kdhc/infoOthbc/infoPrmlgt/list.do?searchPublictRealmCd=G01&menuNo=200013"
rec['path'][3] = cats[0]
rec['vals'][11] = url0; rec['klink'] = url0
rec['vals'][12] = '게시판'; rec['vals'][13] = g7M['cats']['G01'][0]
rec['vals'][14] = '어문'; rec['vals'][15] = '미부착'
rec['newcells'] = {7, 11, 13}
OUT.append(rec)
base = rec['path'][:3]
for i in range(2, 9):
code = 'G0%d' % i
url = "https://www.kdhc.co.kr/kdhc/infoOthbc/infoPrmlgt/list.do?searchPublictRealmCd=%s&menuNo=200013" % code
OUT.append(newrec(base + [cats[i - 1]], K=url, L='게시판', M=g7M['cats'][code][0], N='어문'))
continue
if p and p['type'] in ('child', 'sibling'):
if p['type'] == 'child':
rec['path'][3] = p['self']
rec['newcells'] = {7}
OUT.append(rec)
base = rec['path'][:3]
for it in p['new']:
L, M, N = it['L'], it['M'], it['N']; mn = it['menuNo']
if mn in OV:
L, M, N = OV[mn]
site = (L == '사이트')
OUT.append(newrec(base + [it['label']], K=it['url'], L=L, M=M, N=N, site=site))
else:
OUT.append(rec)
base = rec['path'][:2]
for it in p['new']:
L, M, N = it['L'], it['M'], it['N']; mn = it['menuNo']
if mn in OV:
L, M, N = OV[mn]
site = (L == '사이트')
OUT.append(newrec(base + [it['label']], K=it['url'], L=L, M=M, N=N, site=site))
else:
OUT.append(rec)
# unmerge data merges
for m in list(ws.merged_cells.ranges):
if m.min_row >= 3:
ws.unmerge_cells(str(m))
endrow = max(DATA0, 2 + len(OUT))
for r in range(3, endrow + 1):
for c in COLS:
cell = ws.cell(r, c); cell.value = None; cell.hyperlink = None
for i, rec in enumerate(OUT):
rr = 3 + i
for k in range(7):
ws.cell(rr, 4 + k).value = rec['path'][k]
ws.cell(rr, 2).value = i + 1
ws.cell(rr, 3).value = ORG
for c in range(11, 28):
ws.cell(rr, c).value = rec['vals'].get(c)
if rec['klink']:
ws.cell(rr, 11).hyperlink = Hyperlink(ref='K%d' % rr, target=rec['klink'])
for c in COLS:
if rec['new']:
ws.cell(rr, c)._style = copy.copy(tmpl[c])
else:
ws.cell(rr, c)._style = copy.copy(rec['styles'][c])
# K hyperlink style only if there is a url
if rec['vals'].get(11):
ws.cell(rr, 11)._style = copy.copy(tmpl[11])
else:
ws.cell(rr, 11)._style = copy.copy(tmpl[12])
if rec.get('rowh'):
ws.row_dimensions[rr].height = rec['rowh']
if rec['new']:
for c in range(4, 16):
ws.cell(rr, c).fill = copy.copy(BLUE)
elif rec.get('newcells'):
for c in rec['newcells']:
ws.cell(rr, c).fill = copy.copy(BLUE)
NROW = 2 + len(OUT)
def make_merges():
# D-J filled in every row; merge maximal runs where (D..c) tuple equal & value non-empty
for c in range(4, 11):
r = 3
while r <= NROW:
v = ws.cell(r, c).value
if v in (None, ''):
r += 1; continue
key = tuple(ws.cell(r, pc).value for pc in range(4, c + 1))
r2 = r
while r2 + 1 <= NROW and tuple(ws.cell(r2 + 1, pc).value for pc in range(4, c + 1)) == key:
r2 += 1
if r2 > r:
# blank the non-top cells then merge
for rr in range(r + 1, r2 + 1):
ws.cell(rr, c).value = None
ws.merge_cells(start_row=r, start_column=c, end_row=r2, end_column=c)
r = r2 + 1
make_merges()
wb.save(PATH)
print('OUT rows:', len(OUT), 'final last row:', NROW)