공공기관2 작업 중. _temp 몽타주(재생성가능)는 제외. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
87 lines
4.9 KiB
Python
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)))
|