공공기관2 작업 중. _temp 몽타주(재생성가능)는 제외. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
119 lines
4.2 KiB
Python
119 lines
4.2 KiB
Python
"""고용노동부 — 사이트맵 vs 엑셀 비교."""
|
|
import sys, io, json
|
|
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
|
|
|
with open(r'D:\01.프로젝트\DB수집\2주차\검토_리포트\excel_data.json', encoding='utf-8') as f:
|
|
excel = json.load(f)
|
|
with open(r'D:\01.프로젝트\DB수집\2주차\검토_리포트\moel_sitemap_tree.json', encoding='utf-8') as f:
|
|
tree = json.load(f)
|
|
|
|
moel_excel = excel['고용노동부']
|
|
flat = tree['flat']
|
|
|
|
# 트리에서 (path, url) 매핑 만들기
|
|
tree_urls = {} # url -> path
|
|
tree_paths = set() # tuple(path)
|
|
for node in flat:
|
|
path = tuple(node['path'])
|
|
tree_paths.add(path)
|
|
if node.get('absUrl'):
|
|
tree_urls[node['absUrl']] = path
|
|
|
|
# URL 정규화 — 쿼리 파라미터 제거 비교용
|
|
def norm(u):
|
|
if not u: return u
|
|
return u.split('?')[0].rstrip('/')
|
|
|
|
tree_urls_norm = {norm(k): v for k, v in tree_urls.items()}
|
|
|
|
print(f'엑셀 행 수 (고용노동부): {len(moel_excel)}')
|
|
print(f'사이트맵 노드 수: {len(flat)}')
|
|
print(f'사이트맵 URL 있는 노드: {len(tree_urls)}')
|
|
|
|
# 엑셀 각 행의 D/E/F/G/H/I/J path를 만들어서 트리와 비교
|
|
mismatches = [] # 불일치
|
|
matched = 0
|
|
no_url_in_tree = 0 # URL이 트리에 없음
|
|
url_path_diff = 0 # URL은 있는데 path가 다름
|
|
|
|
# 엑셀의 외부링크 행은 제외 (S='외부링크' or URL이 다른 도메인)
|
|
for r in moel_excel:
|
|
K = r['K']
|
|
if not K or r['S'] == '외부링크' or 'moel.go.kr' not in (K if isinstance(K, str) else ''):
|
|
continue
|
|
# 엑셀 path 구성: D, E, F, G, H, I, J 순으로 비어있지 않은 값들
|
|
excel_path = tuple(v for v in [r['D'], r['E'], r['F'], r['G'], r['H'], r['I'], r['J']] if v)
|
|
|
|
# 트리에서 같은 URL 찾기
|
|
nu = norm(K)
|
|
if nu in tree_urls_norm:
|
|
tree_path = tree_urls_norm[nu]
|
|
if tree_path == excel_path:
|
|
matched += 1
|
|
else:
|
|
url_path_diff += 1
|
|
mismatches.append({
|
|
'type': 'PATH_DIFF',
|
|
'row': r['row'],
|
|
'url': K,
|
|
'excel_path': list(excel_path),
|
|
'tree_path': list(tree_path),
|
|
})
|
|
else:
|
|
no_url_in_tree += 1
|
|
mismatches.append({
|
|
'type': 'URL_NOT_IN_SITEMAP',
|
|
'row': r['row'],
|
|
'url': K,
|
|
'excel_path': list(excel_path),
|
|
})
|
|
|
|
print(f'\n=== 매칭 결과 ===')
|
|
print(f' 완전 일치: {matched}')
|
|
print(f' URL 동일, path 다름: {url_path_diff}')
|
|
print(f' URL이 사이트맵에 없음: {no_url_in_tree}')
|
|
|
|
# 사이트맵에는 있는데 엑셀에 없는 항목 — 누락
|
|
excel_urls = set()
|
|
for r in moel_excel:
|
|
K = r['K']
|
|
if K and isinstance(K, str):
|
|
excel_urls.add(norm(K))
|
|
|
|
missing_in_excel = []
|
|
for url, path in tree_urls_norm.items():
|
|
if url not in excel_urls:
|
|
missing_in_excel.append({'url': url, 'tree_path': list(path)})
|
|
|
|
print(f'\n=== 사이트맵에는 있는데 엑셀에 없는 URL (잠재적 누락) ===')
|
|
print(f' 개수: {len(missing_in_excel)}')
|
|
|
|
# D열 매칭 (대분류 일치 여부)
|
|
excel_D_set = set(r['D'] for r in moel_excel if r['D'])
|
|
tree_D_set = set(tree['roots'])
|
|
print(f'\n=== D열 (메뉴명) 비교 ===')
|
|
print(f' 엑셀: {sorted(excel_D_set)}')
|
|
print(f' 사이트맵: {sorted(tree_D_set)}')
|
|
print(f' 엑셀에 있는데 사이트맵에 없음: {excel_D_set - tree_D_set}')
|
|
print(f' 사이트맵에 있는데 엑셀에 없음: {tree_D_set - excel_D_set}')
|
|
|
|
# 결과 저장
|
|
result = {
|
|
'site': '고용노동부',
|
|
'excel_rows': len(moel_excel),
|
|
'tree_nodes': len(flat),
|
|
'matched': matched,
|
|
'url_path_diff': url_path_diff,
|
|
'url_not_in_sitemap': no_url_in_tree,
|
|
'missing_in_excel': len(missing_in_excel),
|
|
'D_excel': sorted(excel_D_set),
|
|
'D_tree': sorted(tree_D_set),
|
|
'D_excel_only': sorted(excel_D_set - tree_D_set),
|
|
'D_tree_only': sorted(tree_D_set - excel_D_set),
|
|
'mismatches_sample': mismatches[:30],
|
|
'missing_in_excel_sample': missing_in_excel[:20],
|
|
}
|
|
with open(r'D:\01.프로젝트\DB수집\2주차\검토_리포트\moel_compare.json', 'w', encoding='utf-8') as f:
|
|
json.dump(result, f, ensure_ascii=False, indent=2)
|
|
print('\nsaved moel_compare.json')
|