공공기관2 작업 중. _temp 몽타주(재생성가능)는 제외. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
88 lines
4.6 KiB
Python
88 lines
4.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
# 국악방송(27) O 가시성 재검증: 화면에 실제 노출된(offsetParent!=null) 공공누리 라이선스 텍스트만 인정.
|
|
# 현재 O!=미부착 행만 재판정(숨김텍스트→미부착). 사용: [--apply]
|
|
import openpyxl, glob, os, re, sys, shutil, time
|
|
from playwright.sync_api import sync_playwright
|
|
from openpyxl.styles import PatternFill
|
|
BLUE=PatternFill(fill_type='solid',fgColor='FFBDD7EE'); APPLY='--apply' in sys.argv
|
|
def fixdom(u): return str(u).replace('https://new.igbf.kr','http://www.igbf.kr').replace('http://new.igbf.kr','http://www.igbf.kr')
|
|
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]
|
|
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
|
|
# 화면 보이는 공공누리 라이선스 텍스트 수집 JS
|
|
JS=r'''()=>{
|
|
let out=[];
|
|
let walk=document.querySelectorAll('body *');
|
|
for(const e of walk){
|
|
if(e.offsetParent===null && e.tagName!=='BODY') continue; // 숨김 제외
|
|
let own=[...e.childNodes].filter(n=>n.nodeType===3).map(n=>n.textContent).join(' ');
|
|
if(/공공누리/.test(own) && /조건에\s*따라\s*이용|이용\s*가능/.test(own)) out.push(own.replace(/\s+/g,' ').trim());
|
|
}
|
|
return out;
|
|
}'''
|
|
def types_from_visible(texts):
|
|
types=set(); ai=False
|
|
for t in texts:
|
|
num=re.search(r'제\s*([1-4])\s*유형', t)
|
|
if num: types.add(int(num.group(1)))
|
|
else:
|
|
commerce='상업적' in t and '금지' in t
|
|
change='변경' in t and '금지' in t
|
|
if '출처표시' in t:
|
|
if commerce and change: types.add(4)
|
|
elif change: types.add(3)
|
|
elif commerce: types.add(2)
|
|
else: types.add(1)
|
|
if '인공지능' in t or re.search(r'AI\s*학습|학습용',t): ai=True
|
|
return types, ai
|
|
def compose(types,ai):
|
|
parts=['%d유형'%t for t in sorted(types)]
|
|
if ai: parts.append('AI유형')
|
|
return ','.join(parts) if parts else '미부착'
|
|
targets=[r for r in range(3,ws.max_row+1) if ws.cell(r,2).value is not None and str(ws.cell(r,15).value or '') not in ('미부착','None','')]
|
|
print('재검증 대상(현재 부착) %d행'%len(targets))
|
|
plan={}
|
|
with sync_playwright() as pw:
|
|
br=pw.chromium.launch(); pg=br.new_page(viewport={'width':1280,'height':2200})
|
|
def visit(u):
|
|
try:
|
|
pg.goto(fixdom(u),timeout=25000,wait_until='domcontentloaded'); pg.wait_for_timeout(900); pg.mouse.wheel(0,3000); pg.wait_for_timeout(400)
|
|
return pg.evaluate(JS)
|
|
except Exception: return []
|
|
for r in targets:
|
|
u=str(ws.cell(r,11).value or ''); L=ws.cell(r,12).value
|
|
texts=visit(u)
|
|
if L=='게시판':
|
|
h=pg.content(); base=u.split('&state=')[0].split('#')[0]
|
|
ids=[]
|
|
for pn in ('bIdx','recordidx'): ids+= [(pn,v) for v in list(dict.fromkeys(re.findall(pn+r'=(\d+)',h)))[:4]]
|
|
ids+=[('idx',v) for v in list(dict.fromkeys(re.findall(r'state=view[^\"\']*?idx=(\d+)|[?&]idx=(\d+)[^\"\']*?state=view',h)))[:0]]
|
|
for v in list(dict.fromkeys(re.findall(r'[?&]idx=(\d+)',h)))[:4]: ids.append(('idx',v))
|
|
seen=set()
|
|
for pn,v in ids:
|
|
if (pn,v) in seen: continue
|
|
seen.add((pn,v)); sep='&' if '?' in base else '?'
|
|
texts+=visit(base+sep+'state=view&'+pn+'='+v)
|
|
t,ai=types_from_visible(texts); plan[r]=compose(t,ai)
|
|
time.sleep(0.02)
|
|
br.close()
|
|
chg=[(r,str(ws.cell(r,15).value or ''),plan[r]) for r in targets if plan[r]!=str(ws.cell(r,15).value or '')]
|
|
print('정정 %d행:'%len(chg))
|
|
for r,cur,new in chg: print(' r%d [%s>%s>%s] %s -> %s'%(r,eff(r,4) or '',eff(r,5) or '',ws.cell(r,6).value or '',cur,new))
|
|
if not APPLY: print('DRY'); sys.exit(0)
|
|
mt=os.path.getmtime(xp); wb=openpyxl.load_workbook(xp); ws=wb.active
|
|
for r,cur,new in chg:
|
|
if ws.cell(r,2).value is not None: ws.cell(r,15).value=new; ws.cell(r,15).fill=BLUE
|
|
try:
|
|
if os.path.getmtime(xp)==mt:
|
|
shutil.copy(xp, os.path.join(d,'_backup',os.path.basename(xp).replace('.xlsx','_backup_O가시성정정전.xlsx'))); wb.save(xp); print('saved %d행'%len(chg))
|
|
else: print('ABORT(변경됨)')
|
|
except PermissionError: print('LOCKED')
|