공공기관2 작업 중. _temp 몽타주(재생성가능)는 제외. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
108 lines
4.7 KiB
Python
108 lines
4.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""순창 LNB 4차하위 전개(자동차등록안내식): M>1 페이지(=LNB 부모메뉴, URL은 첫자식)를
|
|
좌측메뉴 자식들로 펼침. 부모행 M→1·lc+1=첫자식, 나머지 자식 행 삽입, lc병합, process_row.
|
|
가드: 부모라벨==행라벨 & 자식수>=2. 사용: python -X utf8 _순창_LNB하위.py [--write]
|
|
"""
|
|
import sys, os, re, 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수집\작업파일\광역_사이트맵\전북특별자치도\7.순창군\전북특별자치도_순창군.xlsx'
|
|
BASE='https://www.sunchang.go.kr'
|
|
SESS=M.make_session()
|
|
|
|
def clean(t): return re.sub(r'하위메뉴.*','',t or '').strip()
|
|
def muid(u):
|
|
mm=re.search(r'menuUid=([0-9a-f]+)',u or ''); return mm.group(1) if mm else None
|
|
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 extract(url):
|
|
soup=M.fetch(SESS,url)
|
|
if soup is None: return None,None
|
|
lnb=soup.select_one('.lnb')
|
|
if not lnb: return None,None
|
|
mid=muid(url)
|
|
target=next((a for a in lnb.find_all('a',href=True) if mid and mid in a['href']),None)
|
|
if not target: return None,None
|
|
li=target.find_parent('li'); pul=li.find_parent('ul') if li else None
|
|
if not pul: return None,None
|
|
pli=pul.find_parent('li'); plabel=clean(pli.find('a').get_text()) if (pli and pli.find('a')) else None
|
|
ch=[(clean(c.find('a').get_text()), urljoin(BASE,c.find('a')['href']))
|
|
for c in pul.find_all('li',recursive=False) if c.find('a',href=True)]
|
|
return plabel,ch
|
|
|
|
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 main():
|
|
write='--write' in sys.argv
|
|
wb=openpyxl.load_workbook(XLSX); ws=wb.active
|
|
C=ws.cell(3,3).value
|
|
cands=[]
|
|
for r in range(3,ws.max_row+1):
|
|
if ws.cell(r,12).value!='페이지': continue
|
|
Mv=ws.cell(r,13).value
|
|
if not(isinstance(Mv,int) and Mv>1): continue
|
|
lc=leafcol(ws,r)
|
|
if not lc or lc>=10: continue
|
|
if ws.cell(r,lc+1).value not in (None,''): continue # 이미 전개됨
|
|
K=ws.cell(r,11).value
|
|
if not(isinstance(K,str) and 'menuUid=' in K): continue
|
|
cands.append((r,lc,Mv,K,ws.cell(r,lc).value))
|
|
plan=[]
|
|
for r,lc,Mv,K,lab in cands:
|
|
plabel,ch=extract(K)
|
|
if plabel and clean(lab)==plabel and ch and len(ch)>=2:
|
|
plan.append((r,lc,Mv,ch,lab))
|
|
else:
|
|
print(' SKIP r%d %s (부모=%s 자식=%s)'%(r,lab,plabel,len(ch) if ch else None))
|
|
print('전개대상 %d개 (가드통과)'%len(plan))
|
|
if not write:
|
|
for r,lc,Mv,ch,lab in plan:
|
|
print(' r%d %s M%s→%d자식'%(r,lab,Mv,len(ch)))
|
|
return
|
|
shutil.copy(XLSX, XLSX.replace('.xlsx','_backup_LNB하위전.xlsx'))
|
|
tot=0
|
|
for r,lc,Mv,ch,lab in sorted(plan,key=lambda t:-t[0]): # bottom-up
|
|
# 부모행 = 첫자식
|
|
ws.cell(r,lc+1).value=ch[0][0]
|
|
ws.cell(r,11).value=ch[0][1]
|
|
ws.cell(r,13).value=1
|
|
rest=ch[1:]; n=len(rest)
|
|
if n:
|
|
remap_insert(ws,r+1,n)
|
|
for i,(clab,curl) in enumerate(rest):
|
|
rr=r+1+i
|
|
out=M.process_row(SESS,curl,M.BODY_SEL)
|
|
ws.cell(rr,3).value=C
|
|
ws.cell(rr,lc+1).value=clab
|
|
ws.cell(rr,11).value=curl
|
|
ws.cell(rr,12).value=out['L'] or '페이지'
|
|
ws.cell(rr,13).value=out['M'] if out['M']!='' else 1
|
|
ws.cell(rr,14).value=out['N']
|
|
ws.cell(rr,15).value=out['O']; ws.cell(rr,16).value=out['P']; ws.cell(rr,17).value=out['Q']
|
|
ws.row_dimensions[rr].height=15
|
|
ws.merge_cells(start_row=r,start_column=lc,end_row=r+n,end_column=lc)
|
|
tot+=n
|
|
print(' r%d %s +%d'%(r,lab,n))
|
|
for r in range(3,ws.max_row+1):
|
|
v=ws.cell(r,11).value; cell=ws.cell(r,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()
|