# -*- coding: utf-8 -*- """임실 104~끝 menuCd 하위메뉴 재구성. F-아이템(소분류 ...000 랜딩, 자식보유)의 세부 자식을 G로 전개. 기존 라벨없는 자식행 보정 + 누락 자식 삽입 + 스타일복사 + F병합. 자식수<기존행이면 SKIP(보고). 사용: python -X utf8 _임실_submenu.py [--write] """ import sys, os, re, copy, shutil, importlib.util from urllib.parse import urljoin import openpyxl from openpyxl.worksheet.hyperlink import Hyperlink HERE=os.path.dirname(os.path.abspath(__file__)) s=importlib.util.spec_from_file_location('m',os.path.join(HERE,'_jeonbuk_phase234_all.py')) M=importlib.util.module_from_spec(s); s.loader.exec_module(M) XLSX=r'D:\01.프로젝트\DB수집\작업파일\광역_사이트맵\전북특별자치도\10.임실군\전북특별자치도_임실군.xlsx' BASE='https://www.imsil.go.kr' START=104 SESS=M.make_session() BOARD_KW=re.compile(r'공지사항|고시공고|입찰공고|입법예고|자료실|갤러리|보도자료|새소식|알림|게시판') def mcd(u): mm=re.search(r'menuCd=(\w+)',u or ''); return mm.group(1) if mm else None def clean(t): return re.sub(r'새창열림|\s+',' ',t or '').strip() def leafcol(ws,r): for c in range(10,3,-1): if ws.cell(r,c).value not in (None,''): return c return None def children_of(url, fmc): soup=M.fetch(SESS,url) if soup is None: return None pre=fmc[:-3] out={} for a in soup.find_all('a',href=True): c=mcd(a['href']) if c and c!=fmc and c.startswith(pre) and len(c)==len(fmc) and c[len(pre):]!='000': out[c]=(clean(a.get_text()), urljoin(BASE,a['href'])) return [out[k] for k in sorted(out)] def LMN(label): if BOARD_KW.search(label or ''): return '게시판',0,'어문' return '페이지',1,'어문' def copy_style(ws, sr, dr): for c in range(2,19): s=ws.cell(sr,c); d=ws.cell(dr,c) d.font=copy.copy(s.font); d.alignment=copy.copy(s.alignment) d.border=copy.copy(s.border); d.fill=copy.copy(s.fill); d.number_format=s.number_format def remap_insert(ws, ins, n): ranges=[(x.min_col,x.min_row,x.max_col,x.max_row) for x in list(ws.merged_cells.ranges)] for x in list(ws.merged_cells.ranges): ws.unmerge_cells(str(x)) ws.insert_rows(ins,n) for mc,mr,xc,xr in ranges: if mr>=ins: mr+=n; xr+=n elif xr>=ins: xr+=n ws.merge_cells(start_row=mr,start_column=mc,end_row=xr,end_column=xc) def build_plan(ws): plan=[] r=START while r<=ws.max_row: K=ws.cell(r,11).value; lc=leafcol(ws,r) fmc=mcd(K) if isinstance(K,str) else None if not fmc or lc!=6 or not fmc.endswith('000'): r+=1; continue ch=children_of(K,fmc) if not ch or len(ch)<1: r+=1; continue # consume following group rows (menuCd startswith prefix) pre=fmc[:-3]; grp=[r]; k=r+1 while k<=ws.max_row: kc=mcd(ws.cell(k,11).value) if kc and kc.startswith(pre) and kc!=fmc: grp.append(k); k+=1 else: break plan.append((r,lc,ws.cell(r,6).value,grp,ch)) r=k return plan def main(): write='--write' in sys.argv wb=openpyxl.load_workbook(XLSX); ws=wb.active C=ws.cell(3,3).value plan=build_plan(ws) print('F-아이템(자식보유) %d개'%len(plan)) skip=[x for x in plan if len(x[3])>len(x[4])] for r,lc,lab,grp,ch in skip: print(' SKIP r%d %s 기존행%d>자식%d'%(r,lab,len(grp),len(ch))) plan=[x for x in plan if len(x[3])<=len(x[4])] if not write: for r,lc,lab,grp,ch in plan[:25]: print(' r%d %s 기존%d→자식%d(+%d): %s'%(r,lab,len(grp),len(ch),len(ch)-len(grp),[t for t,_ in ch])) print('총 신규삽입=%d'%sum(len(ch)-len(grp) for r,lc,lab,grp,ch in plan)) return shutil.copy(XLSX, XLSX.replace('.xlsx','_backup_submenu전.xlsx')) tot=0 for r,lc,lab,grp,ch in sorted(plan,key=lambda t:-t[0]): # bottom-up n_ins=len(ch)-len(grp) if n_ins>0: remap_insert(ws, grp[-1]+1, n_ins) # 모든 자식 배치 (grp[0]은 F유지, 나머지 F=None) for i,(clab,curl) in enumerate(ch): rr=r+i if i>=len(grp): copy_style(ws, r, rr) ws.cell(rr,3).value=C l,mm,nn=LMN(clab) ws.cell(rr,7).value=clab # G ws.cell(rr,11).value=curl ws.cell(rr,12).value=l; ws.cell(rr,13).value=mm; ws.cell(rr,14).value=nn ws.cell(rr,15).value=None; ws.cell(rr,16).value=None; ws.cell(rr,17).value=None if i>0: ws.cell(rr,6).value=None # F=None (병합내부) ws.row_dimensions[rr].height=ws.row_dimensions[r].height or 15 if len(ch)>1: ws.merge_cells(start_row=r,start_column=6,end_row=r+len(ch)-1,end_column=6) tot+=max(0,n_ins) print(' r%d %s 자식%d(+%d)'%(r,lab,len(ch),max(0,n_ins))) for rr in range(3,ws.max_row+1): v=ws.cell(rr,11).value; cell=ws.cell(rr,11) if isinstance(v,str) and v.startswith('http'): cell.hyperlink=Hyperlink(ref=cell.coordinate,target=v) else: cell.hyperlink=None wb.save(XLSX) print('적용: 신규삽입+%d행 · 스타일복사 · 백업'%tot) if __name__=='__main__': main()