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

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')