DB_JOB/작업파일/완료_1-2주차/2주차/검토_리포트/compare_moel.py
hehihoho3 df16c98366 백업: DB수집 전체 스냅샷 (공공기관2 정리 전)
공공기관2 작업 중. _temp 몽타주(재생성가능)는 제외.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 18:15:40 +09:00

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')