import sys, io sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') import openpyxl PKG = r'D:\01.프로젝트\DB수집\작업파일\_제출패키지_2026-06-03\프리랜서1\충청남도_부여군.xlsx' wb = openpyxl.load_workbook(PKG); ws = wb.active # rows where K has URL but L/ or where M/N/O blank on 게시판/페이지 print('=== content rows with missing L(형태) ===') for r in range(3, ws.max_row+1): if ws.cell(r,2).value in (None,''): continue k=ws.cell(r,11).value; l=ws.cell(r,12).value if (k not in (None,'')) and (l in (None,'')): print(f' r{r} B={ws.cell(r,2).value} K={k!r} L={l!r}') print('\n=== L distribution + M/N/O blanks ===') from collections import Counter lc=Counter() mblank=[]; nblank=[] for r in range(3, ws.max_row+1): if ws.cell(r,2).value in (None,''): continue l=ws.cell(r,12).value; lc[l]+=1 m=ws.cell(r,13).value; n=ws.cell(r,14).value if l in ('페이지','게시판') and m in (None,''): mblank.append(r) if l in ('페이지','게시판') and n in (None,''): nblank.append(r) print('L:', dict(lc)) print('M blank(페이지/게시판):', len(mblank), mblank[:20]) print('N blank(페이지/게시판):', len(nblank), nblank[:20]) # single-row D/E/F merges & gaps: list D merges to see grouping print('\n=== D-column merges (메뉴명 groups) ===') dm=sorted([m for m in ws.merged_cells.ranges if m.min_col==4 and m.min_row>=3], key=lambda x:x.min_row) prev_end=2 for m in dm: gap = '' if m.min_row==prev_end+1 else f' <-- GAP rows {prev_end+1}..{m.min_row-1}' print(f' D{m.min_row}:{m.max_row} = {ws.cell(m.min_row,4).value!r}{gap}') prev_end=m.max_row # rows after last D merge if prev_end < ws.max_row: # check if remaining rows have D values (single-cell, unmerged) rem=[r for r in range(prev_end+1, ws.max_row+1) if ws.cell(r,2).value not in (None,'')] print(f' (rows after last D-merge: {rem[:10]} ... {len(rem)} rows, D values e.g. {[ws.cell(r,4).value for r in rem[:5]]})') print('\n=== row heights anomaly (non-15) ===') hh=[(r, ws.row_dimensions[r].height) for r in range(1, ws.max_row+1) if ws.row_dimensions[r].height not in (15, None)] print('non-15 heights:', len(hh), hh[:20])