공공기관2 작업 중. _temp 몽타주(재생성가능)는 제외. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
62 lines
3.1 KiB
Python
62 lines
3.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
import json
|
|
from playwright.sync_api import sync_playwright
|
|
SITES=[(2,'강원대학교병원','https://www.knuh.or.kr'),(3,'건강보험심사평가원','https://www.hira.or.kr'),
|
|
(8,'경제인문사회연구회','https://www.nrc.re.kr'),(11,'국가생명윤리정책원','https://nibp.kr'),
|
|
(12,'국가유산진흥원','https://www.kh.or.kr'),(14,'국립공원공단','https://www.knps.or.kr'),
|
|
(16,'국립낙동강생물자원관','https://www.nnibr.re.kr'),(19,'국립중앙의료원','https://www.nmc.or.kr'),
|
|
(27,'국악방송','http://www.igbf.kr')]
|
|
# walk: best megamenu = ul with most a AND nested ul ANYWHERE (not just direct child); walk sub-ul found anywhere in li
|
|
WALK='''()=>{
|
|
const txt=el=>(el.textContent||'').replace(/\\s+/g,' ').trim();
|
|
let best=null,bestScore=0;
|
|
document.querySelectorAll('ul').forEach(ul=>{
|
|
let links=ul.querySelectorAll('a').length, nested=ul.querySelectorAll('ul').length;
|
|
let score=links+nested*3;
|
|
if(links>=6 && links<600 && nested>=2 && score>bestScore){bestScore=score;best=ul;}
|
|
});
|
|
if(!best) return {err:'none'};
|
|
function walk(ul,lvl,out){
|
|
[...ul.children].filter(li=>li.tagName==='LI').forEach(li=>{
|
|
let a=li.querySelector(':scope>a,:scope>button,:scope>p>a,:scope>div>a,:scope>span>a,:scope>h3>a,:scope>strong>a');
|
|
if(!a) a=li.querySelector('a');
|
|
let t=a?txt(a):''; let href=a?(a.getAttribute('href')||''):'';
|
|
if(t) out.push({lvl,t:t.slice(0,40),href:href.slice(0,90)});
|
|
let sub=li.querySelector(':scope>ul'); if(!sub){let dv=li.querySelector(':scope>div');if(dv)sub=dv.querySelector('ul');}
|
|
if(sub) walk(sub,lvl+1,out);
|
|
});
|
|
return out;
|
|
}
|
|
return {cls:(typeof best.className==='string'?best.className:''),tree:walk(best,1,[])};
|
|
}'''
|
|
out={}
|
|
with sync_playwright() as p:
|
|
b=p.chromium.launch(headless=True); pg=b.new_page()
|
|
for no,name,base in SITES:
|
|
try:
|
|
pg.goto(base, wait_until='domcontentloaded', timeout=35000); pg.wait_for_timeout(1800)
|
|
# try hover each top menu to reveal submenus
|
|
try:
|
|
tops=pg.query_selector_all('nav li, .gnb li, #gnb li, header li')
|
|
for el in tops[:10]:
|
|
try: el.hover(timeout=600)
|
|
except: pass
|
|
pg.wait_for_timeout(400)
|
|
except: pass
|
|
r=pg.evaluate(WALK)
|
|
if 'tree' in r:
|
|
lv={}
|
|
for x in r['tree']: lv[x['lvl']]=lv.get(x['lvl'],0)+1
|
|
print('%d.%s cls=%s items=%d 깊이=%s'%(no,name,r['cls'][:22],len(r['tree']),lv))
|
|
out[no]={'name':name,'base':base,**r}
|
|
else:
|
|
print('%d.%s 실패'%(no,name)); out[no]={'name':name,'base':base,'err':1}
|
|
except Exception as e:
|
|
print('%d.%s ERR %s'%(no,name,str(e)[:35])); out[no]={'name':name,'base':base,'err':str(e)[:35]}
|
|
b.close()
|
|
import os
|
|
existing=json.load(open('_gnb_trees.json',encoding='utf-8')) if os.path.exists('_gnb_trees.json') else {}
|
|
for k,v in out.items(): existing[str(k)]=v
|
|
json.dump(existing, open('_gnb_trees.json','w',encoding='utf-8'), ensure_ascii=False, indent=1)
|
|
print('merged to _gnb_trees.json')
|