# -*- coding: utf-8 -*- # 국악방송(27) 전 ?sub_num= 페이지의 좌측 ul.sub_menu 형제그룹 스캔 → 시트 미존재 sub_num 보고. import openpyxl, glob, os, re, urllib.request, ssl, http.cookiejar, time from bs4 import BeautifulSoup ctx=ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE cj=http.cookiejar.CookieJar(); op=urllib.request.build_opener(urllib.request.HTTPSHandler(context=ctx),urllib.request.HTTPCookieProcessor(cj)) op.addheaders=[('User-Agent','Mozilla/5.0')] BASE='http://www.igbf.kr' def fixdom(u): return str(u).replace('https://new.igbf.kr','http://www.igbf.kr').replace('http://new.igbf.kr','http://www.igbf.kr') def g(u): try: return op.open(fixdom(u),timeout=20).read().decode('utf-8','replace') except Exception: return '' DIR=os.path.dirname(os.path.abspath(__file__)) d=[x for x in glob.glob(os.path.join(DIR,'27.*')) if os.path.isdir(x)][0] xp=[p for p in glob.glob(os.path.join(d,'*.xlsx')) if not os.path.basename(p).startswith(('_','~')) and 'conflict' not in os.path.basename(p) and 'backup' not in p][0] ws=openpyxl.load_workbook(xp).active def eff(r,c): v=ws.cell(r,c).value if v is not None: return v for mr in ws.merged_cells.ranges: if mr.min_col==c and mr.min_row<=r<=mr.max_row: return ws.cell(mr.min_row,c).value data=[r for r in range(3,ws.max_row+1) if ws.cell(r,2).value is not None] def subnum(u): m=re.search(r'[?&]sub_num=(\d+)',str(u)); return m.group(1) if m else None sheet_sn=set(subnum(ws.cell(r,11).value) for r in data if subnum(ws.cell(r,11).value)) # 대상: ?sub_num= 단순페이지(program 제외) targets=[r for r in data if re.search(r'gugak_web/\?sub_num=\d+',str(ws.cell(r,11).value or '')) and 'program' not in str(ws.cell(r,11).value or '')] print('대상 %d페이지 sub_menu 스캔...'%len(targets)) seen_group=set(); reports=[] for r in targets: h=g(ws.cell(r,11).value) if not h: continue s=BeautifulSoup(h,'html.parser') cursn=subnum(ws.cell(r,11).value) # 모든 ul.sub_menu / ul.third_menu 그룹 수집 for ul in s.select('ul.sub_menu, ul.third_menu'): items=[] for a in ul.find_all('a',href=True): sn=subnum(a['href']); t=re.sub(r'\s+',' ',a.get_text()).strip() if sn and t: items.append((sn,t)) if len(items)<2: continue key=tuple(sn for sn,_ in items) if key in seen_group: continue seen_group.add(key) missing=[(sn,t) for sn,t in items if sn not in sheet_sn] cur=' '.join(str(x) for x in [eff(r,4),eff(r,5),ws.cell(r,6).value] if x) contains_cur = cursn in [sn for sn,_ in items] reports.append((r,cur,cursn,items,missing,contains_cur)) if missing: print('r%d [%s] (cur=%s) 그룹 %d개 미존재 %d: %s'%(r,cur,cursn,len(items),len(missing),' / '.join('%s(%s)%s'%(t,sn,'★' if sn not in sheet_sn else '') for sn,t in items))) print('\n=== 누락 형제 있는 그룹 ===') for r,cur,cursn,items,missing,cc in reports: if missing: print('r%d [%s] cur자신포함=%s: +%d → %s'%(r,cur,cc,len(missing),', '.join('%s(%s)'%(t,sn) for sn,t in missing))) import json json.dump([(r,cur,cursn,items,missing,cc) for r,cur,cursn,items,missing,cc in reports],open(os.path.join(DIR,'_gugak_subnav.json'),'w',encoding='utf-8'),ensure_ascii=False)