# -*- coding: utf-8 -*- """3.한국의약품안전관리원 GNB 권위트리(.allmenu p.depth1/ul.depth2/depth3/depth4) 재구조화 → _gnb/3.json""" import sys, io, json, warnings sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') warnings.filterwarnings('ignore') from playwright.sync_api import sync_playwright JS = r""" () => { const cont = document.querySelector('.allmenu'); if(!cont) return {err:'no allmenu'}; function childUl(li, cls){ for(const u of li.children){ if(u.tagName==='UL' && u.classList.contains(cls)) return u; } return null; } function directA(li){ for(const a of li.children){ if(a.tagName==='A') return a; } // sometimes wrapped const a=li.querySelector(':scope > a'); return a; } const rows=[]; // top blocks: li containing p.depth1 const blocks = [...cont.querySelectorAll('p.depth1')].map(p=>p.closest('li')); blocks.forEach(b=>{ const p1=b.querySelector(':scope > p.depth1'); const d1label=(p1.textContent||'').trim().replace(/\s+/g,' '); rows.push({depth:1, label:d1label, href:''}); const u2=childUl(b,'depth2'); if(!u2) return; [...u2.children].filter(li=>li.tagName==='LI').forEach(li2=>{ const a2=directA(li2); if(!a2) return; const l2=(a2.textContent||'').trim().replace(/\s+/g,' '); const h2=a2.getAttribute('href')||''; rows.push({depth:2, label:l2, href:h2}); const u3=childUl(li2,'depth3'); if(!u3) return; [...u3.children].filter(li=>li.tagName==='LI').forEach(li3=>{ const a3=directA(li3); if(!a3) return; const l3=(a3.textContent||'').trim().replace(/\s+/g,' '); const h3=a3.getAttribute('href')||''; rows.push({depth:3, label:l3, href:h3}); const u4=childUl(li3,'depth4'); if(!u4) return; [...u4.children].filter(li=>li.tagName==='LI').forEach(li4=>{ const a4=directA(li4); if(!a4) return; const l4=(a4.textContent||'').trim().replace(/\s+/g,' '); const h4=a4.getAttribute('href')||''; rows.push({depth:4, label:l4, href:h4}); }); }); }); }); return {rows}; } """ BASE='https://www.drugsafe.or.kr' with sync_playwright() as p: br=p.chromium.launch(headless=True) ctx=br.new_context(ignore_https_errors=True, viewport={'width':1920,'height':1080}) pg=ctx.new_page() pg.goto(BASE+'/', wait_until='domcontentloaded', timeout=40000) pg.wait_for_timeout(2500) res=pg.evaluate(JS) br.close() if 'err' in res: print('ERR', res['err']); sys.exit(1) # absolutize hrefs, blank javascript:/# out=[] for r in res['rows']: h=r['href'].strip() if h.startswith('javascript:') or h=='#' or h=='': h='' elif h.startswith('/'): h=BASE+h elif h.startswith('http'): pass else: h=BASE+'/'+h out.append({'depth':r['depth'],'label':r['label'],'href':h}) data={'num':3,'name':'한국의약품안전관리원','base':BASE,'sel':'.allmenu(depth1/2/3/4)','gnb':out} json.dump(data, open('_gnb/3.json','w',encoding='utf-8'), ensure_ascii=False, indent=1) import collections dc=collections.Counter(r['depth'] for r in out) print('rows',len(out),'depthdist',dict(dc)) for r in out: print(' '*(r['depth']-1)+f"d{r['depth']} | {r['label'][:42]} | {r['href'][:55]}")