# -*- coding: utf-8 -*- import sys, io, json sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') from playwright.sync_api import sync_playwright URLS = [ "https://www.kesco.or.kr/contents/selectContents.do?contents_id=CKK00006", # 비전핵심가치(공사소개) "https://www.kesco.or.kr/contents/selectContents.do?contents_id=MEB00002", # 사업분야 ] JS = """ () => { // LNB 컨테이너 후보 const cands=[]; document.querySelectorAll('#snb,.snb,.lnb,#lnb,.sub_lnb,[class*=snb],[class*=lnb],[class*=left_menu],aside').forEach(el=>{ const a=el.querySelectorAll('a').length; if(a>=2) cands.push({sel:(el.id?'#'+el.id:'.'+String(el.className).split(' ')[0]), a, d4:el.querySelectorAll('ul.depth4,.depth4').length}); }); cands.sort((x,y)=>y.a-x.a); // 전체 depth ul 클래스 종류 const ulcls=[...new Set([...document.querySelectorAll('ul')].map(u=>String(u.className)).filter(c=>/depth/i.test(c)))]; // depth4 항목들 const d4=[...document.querySelectorAll('ul.depth4')].map(u=>[...u.querySelectorAll(':scope>li>a')].map(a=>a.textContent.trim()+'::'+a.getAttribute('href'))); // 가장 앵커많은 LNB의 전체 트리(ancestor ul depth) const lnb=cands.length?document.querySelector(cands[0].sel):null; let tree=[]; if(lnb){ lnb.querySelectorAll('a').forEach(a=>{let d=0,p=a.parentElement;while(p&&p!==lnb){if(p.tagName==='UL')d++;p=p.parentElement;}tree.push([d,a.textContent.trim(),a.getAttribute('href')]);}); } return {cands:cands.slice(0,5), ulcls, d4, tree}; } """ with sync_playwright() as p: br=p.chromium.launch(headless=True) pg=br.new_context(ignore_https_errors=True, viewport={'width':1600,'height':1000}).new_page() for u in URLS: pg.goto(u, wait_until='domcontentloaded', timeout=30000); pg.wait_for_timeout(2000) r=pg.evaluate(JS) print('\n===', u[-12:], '===') print('LNB cands:', r['cands']) print('ul depth classes:', r['ulcls']) print('depth4 items:', json.dumps(r['d4'], ensure_ascii=False)) print('LNB tree(앞30):') for t in r['tree'][:30]: print(' ', t) br.close()