DB_JOB/작업파일/완료/공공기관/_gugak_N_redo.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

87 lines
4.9 KiB
Python

# -*- coding: utf-8 -*-
# 국악방송(27) N 재작성 엑셀32~끝 + 악기 인페이지탭 M=탭수.
# 3~31 사용자검수 N을 라벨→N 학습 + 도메인 휴리스틱. mtime가드·백업. 사용: [--apply]
import openpyxl, glob, os, re, sys, shutil, time, urllib.request, ssl, http.cookiejar
from openpyxl.styles import PatternFill
from playwright.sync_api import sync_playwright
ctx=ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE
BLUE=PatternFill(fill_type='solid',fgColor='FFBDD7EE'); APPLY='--apply' in sys.argv
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]
mt=os.path.getmtime(xp); wb=openpyxl.load_workbook(xp); ws=wb.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
return None
data=[r for r in range(3,ws.max_row+1) if ws.cell(r,2).value is not None]
def label(r): return str(ws.cell(r,6).value or eff(r,5) or '')
# 1) 3~31 학습: 라벨->N (최빈)
from collections import Counter,defaultdict
learn=defaultdict(Counter)
for r in data:
if r<=31:
learn[label(r)][str(ws.cell(r,14).value or '')]+=1
learned={k:v.most_common(1)[0][0] for k,v in learn.items()}
ORDER={'어문':0,'이미지':1,'영상':2,'오디오':3,'글꼴':4,'3D':5,'기타':6}
def compose(parts):
parts=sorted(set(['어문']+parts),key=lambda x:ORDER.get(x,9))
return ','.join(parts)
# 2) 휴리스틱 (라벨 기반)
def heuristic(r):
lab=label(r); E=str(eff(r,5) or ''); D=str(eff(r,4) or ''); L=ws.cell(r,12).value; M=ws.cell(r,13).value
if (M in (0,'0')) and L=='게시판': return '없음'
# 악기(우리악기 톺아보기 하위, 소개 제외)=탭 인터뷰/연주법/제작과정/음원
if E=='우리악기 톺아보기' and lab not in ('소개',): return compose(['이미지','영상','오디오'])
# 오디오 아카이브
if re.search(r'(음원|반주음악|음반|새음원|교육자료|국악\s*교육)',lab): return compose(['오디오'])
if re.search(r'(명인명창|구술)',lab): return compose(['영상'])
# 영상
if re.search(r'(방송보기|다시보기|동영상|영상|보이는\s*라디오|VOD)',lab): return compose(['영상'])
# 오디오 프로그램
if re.search(r'(특집\s*프로그램)',lab): return compose(['오디오'])
# 사진/이미지
if re.search(r'(사진|갤러리|포토)',lab): return compose(['이미지'])
# 소개/인사말/연혁/CI/비전/조직/채널현황 = 인트로(이미지)
if re.search(r'(소개|인사말|연혁|CI|비전|조직|채널현황|프로그램\s*소개|출연자)',lab): return compose(['이미지'])
# 게시판 텍스트류 / 기타 = 어문
return compose([])
# 3) 악기 M=탭수 (ul.tabtn) 크롤
inst_rows=[r for r in data if eff(r,5)=='우리악기 톺아보기' and label(r)!='소개']
tabcount={}
def fixdom(u): return str(u).replace('https://new.igbf.kr','http://www.igbf.kr')
with sync_playwright() as pw:
br=pw.chromium.launch(); pg=br.new_page()
for r in inst_rows:
try:
pg.goto(fixdom(ws.cell(r,11).value),timeout=25000,wait_until='domcontentloaded'); pg.wait_for_timeout(900)
tabcount[r]=len(pg.query_selector_all('ul.tabtn li a'))
except Exception: tabcount[r]=None
br.close()
print('악기 탭수:',{label(r):tabcount[r] for r in inst_rows})
# 4) 판정: 32~끝
changes=[]; mchanges=[]
for r in data:
if r<32: continue
lab=label(r); cur=str(ws.cell(r,14).value or '')
pred= learned.get(lab) if lab in learned else heuristic(r)
# 우리악기 하위는 항상 휴리스틱(학습라벨 '소개' 충돌 방지)
if eff(r,5)=='우리악기 톺아보기': pred=heuristic(r)
if (ws.cell(r,13).value in (0,'0')) and ws.cell(r,12).value=='게시판': pred='없음'
if pred and pred!=cur: changes.append((r,lab,cur,pred))
# 악기 M=탭수
if r in tabcount and tabcount[r] and ws.cell(r,13).value!=tabcount[r]:
mchanges.append((r,lab,ws.cell(r,13).value,tabcount[r]))
print('학습 라벨수 %d'%len(learned))
print('N 변경 %d행:'%len(changes))
for r,lab,cur,pred in changes: print(' r%d [%s] %s -> %s'%(r,lab,cur,pred))
print('악기 M(탭수) 변경 %d행:'%len(mchanges), [(r,l,o,n) for r,l,o,n in mchanges])
if not APPLY: print('DRY'); sys.exit(0)
for r,lab,cur,pred in changes: ws.cell(r,14).value=pred; ws.cell(r,14).fill=BLUE
for r,lab,o,nv in mchanges: ws.cell(r,13).value=nv; ws.cell(r,13).fill=BLUE
if os.path.getmtime(xp)!=mt: print('ABORT changed'); sys.exit(1)
shutil.copy(xp, os.path.join(d,'_backup',os.path.basename(xp).replace('.xlsx','_backup_N재작성전.xlsx')))
wb.save(xp); print('saved N변경%d M변경%d'%(len(changes),len(mchanges)))