공공기관2 작업 중. _temp 몽타주(재생성가능)는 제외. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
64 lines
2.6 KiB
Python
64 lines
2.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""komipo GNB megamenu 권위트리 추출 → _komipo_tree.json (D,E,F,mnCd,type,url)"""
|
|
import json, re
|
|
from playwright.sync_api import sync_playwright
|
|
UA='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120 Safari/537.36'
|
|
BASE='https://www.komipo.co.kr'
|
|
with sync_playwright() as p:
|
|
b=p.chromium.launch(); pg=b.new_page(user_agent=UA,viewport={'width':1600,'height':2400})
|
|
pg.goto('https://www.komipo.co.kr/fr/realName/main.do?mnCd=FN011101',timeout=40000,wait_until='domcontentloaded'); pg.wait_for_timeout(3000)
|
|
rows=pg.evaluate(r"""()=>{
|
|
const nav=document.querySelector('nav');
|
|
const out=[];
|
|
for(const li1 of nav.querySelectorAll(':scope > ul > li')){
|
|
const D=(li1.querySelector(':scope>a')?.textContent||'').trim().replace(/\s+/g,' ');
|
|
// 중분류 = li.more (depth2 패널 안)
|
|
const mores=li1.querySelectorAll('li.more');
|
|
if(mores.length===0){
|
|
// li.more 없으면 depth3 직접 or 단일
|
|
for(const a of li1.querySelectorAll('ul.depth3 > li > a, ul > li > a')){
|
|
out.push({D,E:'',F:(a.textContent||'').trim().replace(/\s+/g,' '),href:a.getAttribute('href')||''});
|
|
}
|
|
continue;
|
|
}
|
|
for(const m of mores){
|
|
const E=(m.querySelector(':scope>p')?.textContent||'').trim().replace(/\s+/g,' ');
|
|
for(const a of m.querySelectorAll('ul.depth3 > li > a')){
|
|
out.push({D,E,F:(a.textContent||'').trim().replace(/\s+/g,' '),href:a.getAttribute('href')||''});
|
|
}
|
|
}
|
|
}
|
|
return out;
|
|
}""")
|
|
b.close()
|
|
|
|
def parse(href):
|
|
href=(href or '').strip()
|
|
m=re.search(r"goPage\('([A-Z]+)'\s*,\s*'([^']+)'", href)
|
|
if m:
|
|
typ=m.group(1); path=m.group(2)
|
|
url=path if path.startswith('http') else BASE+path
|
|
return typ, url
|
|
if href.startswith('http'):
|
|
return ('EXT' if 'komipo.co.kr' not in href else 'CONTENT'), href
|
|
if href.startswith('/'):
|
|
return 'CONTENT', BASE+href
|
|
return '', ''
|
|
|
|
tree=[]
|
|
for r in rows:
|
|
typ,url=parse(r['href'])
|
|
mn=''
|
|
m=re.search(r'mnCd=([A-Z0-9]+)',url)
|
|
if m: mn=m.group(1)
|
|
tree.append({'D':r['D'],'E':r['E'],'F':r['F'],'type':typ,'url':url,'mnCd':mn})
|
|
json.dump(tree,open('_komipo_tree.json','w',encoding='utf-8'),ensure_ascii=False,indent=1)
|
|
from collections import Counter
|
|
print('총 leaf:',len(tree))
|
|
print('대분류:',list(dict.fromkeys(t['D'] for t in tree)))
|
|
print('type분포:',dict(Counter(t['type'] for t in tree)))
|
|
# 대분류별 중분류
|
|
for D in dict.fromkeys(t['D'] for t in tree):
|
|
es=list(dict.fromkeys(t['E'] for t in tree if t['D']==D))
|
|
print('▶',D,'중분류:',es)
|