DB_JOB/작업파일/공공기관2/_hf_infolist_build.py
hehihoho3 df16c98366 백업: DB수집 전체 스냅샷 (공공기관2 정리 전)
공공기관2 작업 중. _temp 몽타주(재생성가능)는 제외.

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

147 lines
5.5 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- 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 cc<c)
for c in sorted(COLS, reverse=True):
r=3
while r<=endr:
v=ws.cell(r,c).value
if v in (None,''): r+=1; continue
r2=r
while r2+1<=endr and ws.cell(r2+1,c).value==v and upper_same(r,r2+1,c):
r2+=1
if r2>r:
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}")