# -*- coding: utf-8 -*-
"""Python Playwright로 공공기관2 정크사이트 GNB 권위트리 추출 → _gnb\{num}.json.
컨테이너 자동탐지(계층 앵커 최다) + 정크라벨 필터 + 스플래시 진입.
사용: python _gnb_extract.py [num ...]"""
import sys, io, os, json, re, warnings
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
warnings.filterwarnings('ignore')
from playwright.sync_api import sync_playwright

GNB_DIR = r"D:\01.프로젝트\DB수집\작업파일\공공기관2\_gnb"

# num: (name, base, entry_url, container_sel(None=auto))
SITES = {
    1:  ("한국전기안전공사", "https://www.kesco.or.kr", "https://www.kesco.or.kr/main/main.do", "ul#gnb"),
    6:  ("한국중부발전", "https://www.komipo.co.kr", "https://www.komipo.co.kr/kor/main/main.do", "#gnbmenu"),
    7:  ("한국지능정보사회진흥원", "https://www.nia.or.kr", "https://www.nia.or.kr/site/nia_kor/main.do", ".gnb_area"),
    8:  ("한국지식재산보호원", "https://www.koipa.re.kr", "https://www.koipa.re.kr/home/main.do", "#gnb"),
    10: ("한국지역난방공사", "https://www.kdhc.co.kr", "https://www.kdhc.co.kr/", "#gnb"),
    11: ("한국직업능력연구원", "https://www.krivet.re.kr", "https://www.krivet.re.kr/", "#k_gnb"),
    13: ("한국청소년상담복지개발원", "https://www.kyci.or.kr", "https://www.kyci.or.kr/userSite/index.asp", ".mb_gnb"),
    15: ("한국청소년활동진흥원", "https://www.kywa.or.kr", "https://www.kywa.or.kr/main/main.jsp", ".gnb ul.one_depth"),
    16: ("한국체육산업개발", "https://www.ksponco.or.kr", "https://www.ksponco.or.kr/", "#gnb"),
}

JUNK = re.compile(r'바로가기|닫기|열기|검색|전체\s*메뉴|메뉴\s*보기|메인메뉴|서브메뉴|본문\s*바로|주\s*메뉴|TOP|위로|맨위|로그인|로그아웃|회원가입|마이페이지|언어|english|日本|中文|sitemap|즐겨찾기|새창|팝업|로고|이동$|^\s*$', re.I)

EXTRACT_JS = """
(containerSel) => {
  const cont = containerSel ? document.querySelector(containerSel) : null;
  if(!cont) return {err:'no container', rows:[]};
  function labelA(li){
    for(const a of li.querySelectorAll('a, button')){
      let p=a.parentElement, inside=false;
      while(p&&p!==li){ if(p.tagName==='UL'){inside=true;break;} p=p.parentElement; }
      if(inside) continue;
      const t=(a.textContent||'').trim();
      if(t) return a;   // 빈 텍스트(아이콘링크) 건너뜀
    }
    return null;
  }
  function topUls(el){
    return [...el.querySelectorAll('ul')].filter(ul=>{
      let p=ul.parentElement;
      while(p&&p!==el){ if(p.tagName==='UL') return false; p=p.parentElement; }
      return true;
    });
  }
  const rows=[];
  function walk(ul, depth){
    [...ul.children].filter(li=>li.tagName==='LI').forEach(li=>{
      const a=labelA(li);
      if(a){
        const label=(a.textContent||'').trim().replace(/\\s+/g,' ');
        const href=a.tagName==='A'?(a.href||''):'';
        if(label) rows.push({depth, label, href});
      }
      topUls(li).forEach(sub=>walk(sub, depth+1));
    });
  }
  const starts = cont.tagName==='UL' ? [cont] : topUls(cont);
  starts.forEach(u=>walk(u, 1));
  return {sel: containerSel, rows};
}
"""

def clean_rows(rows):
    out=[]
    for r in rows:
        lab=r['label']
        if JUNK.search(lab): continue
        if len(lab)>60: continue
        h=r['href'] or ''
        if h.startswith('javascript') or h.endswith('#') or h=='':
            # 링크없는 카테고리노드는 유지(라벨만), 단 정크 아닐때
            pass
        out.append({'depth':min(r['depth'],5), 'label':lab, 'href':h})
    # depth 정규화: 최소깊이를 1로
    if out:
        md=min(r['depth'] for r in out)
        if md>1:
            for r in out: r['depth']-=(md-1)
    return out

def run(nums):
    with sync_playwright() as p:
        br=p.chromium.launch(headless=True)
        ctx=br.new_context(ignore_https_errors=True, viewport={'width':1920,'height':1080}, user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120 Safari/537.36')
        pg=ctx.new_page()
        for num in nums:
            name, base, url, sel = SITES[num]
            try:
                pg.goto(url, wait_until='domcontentloaded', timeout=30000)
                pg.wait_for_timeout(2500)
                res = pg.evaluate(EXTRACT_JS, sel)
                rows = clean_rows(res.get('rows', []))
                d1 = [r['label'] for r in rows if r['depth']==1]
                data={'num':num,'name':name,'base':base,'gnb':rows}
                with open(os.path.join(GNB_DIR, f'{num}.json'),'w',encoding='utf-8') as f:
                    json.dump(data,f,ensure_ascii=False,indent=1)
                print(f"[{num}.{name}] sel={res.get('sel')} rows={len(rows)} d1={len(d1)} :: {d1[:12]}")
            except Exception as e:
                print(f"[{num}.{name}] 실패: {type(e).__name__}: {e}")
        br.close()

if __name__=='__main__':
    nums=[int(x) for x in sys.argv[1:]] or list(SITES.keys())
    run(nums)
