# -*- coding: utf-8 -*- """KCOPA 공공누리(O) 부착 전수 라이브 재스캔 (2026-06-24) 페이지=본문 opentype0N / 게시판=상세 view.do 샘플 union. 시트 O 대조.""" import openpyxl, requests, re, sys from urllib.parse import urljoin from concurrent.futures import ThreadPoolExecutor requests.packages.urllib3.disable_warnings() H={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'} S=requests.Session(); S.headers.update(H); S.verify=False def get(u): try: return S.get(u,timeout=25).text except Exception: return '' def marks(html): return set(int(d) for d in re.findall(r'opentype0?([1-4])', html, re.I)) def view_links(html, base): h=html.replace('&','&') raw=re.findall(r'(view\.do\?article_seq=\d+)', h)+re.findall(r'(view\.do\?ntt_id=\d+)', h) seen=[] for v in raw: if v not in seen: seen.append(v) return [urljoin(base, v) for v in seen[:12]] def scan_row(args): r,label,L,url=args if not url: return (r,label,L,set(),'NO_URL') html=get(url) if L=='게시판' and 'list.do' in url: vl=view_links(html, url) agg=set() if vl: for d in vl: agg|=marks(get(d)) return (r,label,L,agg,f'bbs {len(vl)}상세') # program/gallery board: mark may be on list/contents itself agg=marks(html) return (r,label,L,agg,'list직접') else: return (r,label,L,marks(html),'page본문') def main(): wb=openpyxl.load_workbook('한국저작권보호원.xlsx'); ws=wb.active rows=[] for r in range(3,98): b=ws.cell(r,2).value L=ws.cell(r,12).value O=ws.cell(r,15).value or '미부착' hl=ws.cell(r,11).hyperlink url=hl.target if hl else ws.cell(r,11).value f=ws.cell(r,6).value or ws.cell(r,5).value rows.append((r,f,L,url,O)) args=[(r,f,L,url) for (r,f,L,url,O) in rows] res={} with ThreadPoolExecutor(max_workers=8) as ex: for out in ex.map(scan_row, args): res[out[0]]=out def parse_O(o): return set(int(d) for d in re.findall(r'([1-4])유형', o or '')) print('ROW | 라벨 | 시트O | 검출 | 판정 | 방법') mismatch=[] for (r,f,L,url,O) in rows: _,_,_,det,how=res[r] sheet=parse_O(O) ok = (det==sheet) tag='OK' if ok else 'MISMATCH' if not ok: mismatch.append((r,f,O,sorted(det),how)) if (det or sheet or not ok): print(f'{r:>3} | {str(f)[:28]:28s} | {O:12s} | {sorted(det)} | {tag} | {how}') print('\n=== MISMATCH', len(mismatch),'건 ===') for m in mismatch: print(m) main()