# -*- coding: utf-8 -*- """주택금융 정보목록 3보드에 분류 카테고리 자식행(게시판) 국소삽입. 전체 unmerge→삽입→fill-down→재병합(D~J)→헤더재병합→B재부번→K링크. mtime가드+백업.""" import sys, io, os, glob sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') from copy import copy import openpyxl from openpyxl.styles import Font BASE = r"D:\01.프로젝트\DB수집\작업파일\공공기관2" fp = [x for x in glob.glob(os.path.join(BASE, "5.*", "*.xlsx")) if "_backup" not in x and "~$" not in x][0] COLS = list(range(4, 11)) # D..J HEADER_MERGES = ['B1:R1', 'S1:W1', 'Y1:AA1'] # (보드URL키, 부모라벨, [(카테고리, srCategoryId, M)]) BOARDS = [ ("sub06_04_01", "표준정보목록", [("감사","24",8),("윤리","25",9),("기획","26",12),("재정","27",4),("법무","28",3),("노무","29",4), ("인사","30",3),("총무","31",23),("회계","32",16),("정보화","33",11),("홍보","34",5),("대외","35",3)], None), ("sub06_04_02", "고유정보목록", [("주택구입","36",21),("주택보증","37",20),("주택연금","38",7),("유동화증권","39",19),("신용회복","40",5),("재무","41",7),("기타","42",20)], None), ("sub06_04_03", "즐겨찾는목록", [("감사","24",5),("윤리","25",5),("기획","26",5),("재정","27",4),("법무","28",3),("노무","29",4), ("인사","30",3),("총무","31",5),("회계","32",5),("정보화","33",5),("홍보","34",5),("대외","35",3)], "즐겨찾는목록 카테고리 건수=페이지표시 기준(확인필요)"), ] mt0 = os.path.getmtime(fp) wb = openpyxl.load_workbook(fp) ws = wb.active # effective 경로 사전(부모 깊이 파악용) def eff_paths(): last = {c: None for c in COLS}; res = {} for r in range(3, ws.max_row+1): for c in COLS: v = ws.cell(r,c).value if v not in (None,''): last[c]=v for cc in COLS: if cc>c: last[cc]=None res[r] = dict(last) return res paths = eff_paths() def find_parent(key, label): for r in range(3, ws.max_row+1): k = str(ws.cell(r,11).value or '') if key in k and 'srCategoryId' not in k: if label in paths[r].values(): return r return None # 삽입 계획 (bottom-up) plans = [] for key, label, cats, note in BOARDS: pr = find_parent(key, label) if not pr: print(f"[{key}/{label}] 부모행 없음 — 스킵"); continue ppath = paths[pr] lc = max([c for c in COLS if ppath.get(c)], default=4) childcol = min(lc+1, 10) base_url = str(ws.cell(pr,11).value).split('?')[0] plans.append((pr, childcol, base_url, cats, note, label)) print(f"[{label}] 부모 r{pr} childcol={childcol} +{len(cats)}") plans.sort(key=lambda x: -x[0]) # 0) 전체 unmerge (insert 전에 — insert_rows의 merge손상 방지) for m in [str(x) for x in ws.merged_cells.ranges]: ws.unmerge_cells(m) # 1) 삽입 (bottom-up) for pr, childcol, base_url, cats, note, label in plans: n = len(cats) ws.insert_rows(pr+1, n) for i,(nm,cid,m) in enumerate(cats): rr = pr+1+i for c in range(2, 28): src = ws.cell(pr,c) if src.has_style: d=ws.cell(rr,c) d.font=copy(src.font); d.fill=copy(src.fill); d.border=copy(src.border) d.alignment=copy(src.alignment); d.number_format=src.number_format ws.cell(rr,3).value = ws.cell(pr,3).value ws.cell(rr,childcol).value = nm ws.cell(rr,11).value = f"{base_url}?mode=list&srCategoryId={cid}" ws.cell(rr,12).value = '게시판' ws.cell(rr,13).value = m ws.cell(rr,14).value = '어문' ws.cell(rr,15).value = '미부착' if note: ws.cell(rr,19).value = note if label == '즐겨찾는목록': ws.cell(pr,12).value = '게시판' # endr endr=2 for r in range(3,ws.max_row+1): if ws.cell(r,2).value is not None or any(ws.cell(r,c).value for c in COLS) or ws.cell(r,11).value: endr=r # 3) fill-down last={c:None for c in COLS} for r in range(3,endr+1): for c in COLS: v=ws.cell(r,c).value if v not in (None,''): last[c]=v for cc in COLS: if cc>c: last[cc]=None for c in COLS: if ws.cell(r,c).value in (None,'') and last[c] not in (None,''): ws.cell(r,c).value=last[c] # 4) 재병합 (동일값+상위동일, 깊은열부터) def upper_same(r1,r2,c): return all(ws.cell(r1,cc).value==ws.cell(r2,cc).value for cc in COLS if ccr: ws.merge_cells(start_row=r,start_column=c,end_row=r2,end_column=c) r=r2+1 # 5) 헤더 재병합 for m in HEADER_MERGES: ws.merge_cells(m) # 6) B재부번 + K링크 bn=0 for r in range(3,endr+1): if any(ws.cell(r,c).value for c in COLS) or ws.cell(r,11).value: bn+=1; ws.cell(r,2).value=bn k=ws.cell(r,11); u=k.value if u and isinstance(u,str) and u.startswith('http'): k.hyperlink=u old=k.font k.font=Font(name=old.name or '맑은 고딕', size=old.size or 11, color='0000FF', underline='single') if abs(os.path.getmtime(fp)-mt0)>0.5: print("⚠️ABORT: mtime 변경(동시편집). 저장안함."); sys.exit(1) wb.save(fp) print(f"저장완료. 데이터행 {bn}")