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

86 lines
4.9 KiB
Python

# -*- coding: utf-8 -*-
# 국악방송(27) radio_program_board.jsp 행 L/M/N 재판별.
# L: 진행자소개&총수<=1→페이지M1 / 총수0→게시판M0(없음) / 그외→게시판M=p.total
# N: 상세 본문 실사진(목록 배너 제외=상세전용 img, size>=140x100, UI패턴 제외) 있으면 어문,이미지 / 없으면 어문
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
cj=http.cookiejar.CookieJar(); op=urllib.request.build_opener(urllib.request.HTTPSHandler(context=ctx),urllib.request.HTTPCookieProcessor(cj))
op.addheaders=[('User-Agent','Mozilla/5.0')]
BLUE=PatternFill(fill_type='solid',fgColor='FFBDD7EE'); APPLY='--apply' in sys.argv
UIPAT=re.compile(r'(logo|footer|header|banner|btn|icon|bg[_-]|[_-]bg|sns|family|arrow|blank|no[_-]?img|sprite|marker|common|onair|chn_|ico_|_kt|_sk|_lg)',re.I)
def fixdom(u): return str(u).replace('https://new.igbf.kr','http://www.igbf.kr').replace('http://new.igbf.kr','http://www.igbf.kr')
def gf(u):
try: return op.open(fixdom(u),timeout=20).read().decode('utf-8','replace')
except: return ''
TOT=re.compile(r'class=\"total\"[^>]*>.*?\((\d+)\)',re.S)
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
rows=[r for r in range(3,ws.max_row+1) if ws.cell(r,2).value is not None and 'radio_program_board.jsp' in str(ws.cell(r,11).value or '')]
print('radio_program_board 행 %d'%len(rows))
JS=r'''()=>[...document.querySelectorAll("img")].filter(i=>i.clientWidth>=140&&i.clientHeight>=100).map(i=>(i.currentSrc||i.src||"").split("/").pop())'''
plan={}
with sync_playwright() as pw:
br=pw.chromium.launch(); pg=br.new_page(viewport={'width':1280,'height':1700})
for r in rows:
u=str(ws.cell(r,11).value or ''); lab=str(ws.cell(r,6).value or '')
h=gf(u); m=TOT.search(h); tot=int(m.group(1)) if m else None
# L/M
if tot==0:
L,M,Nbase=('게시판',0,'없음')
elif re.search(r'진행자|소개',lab) and (tot is None or tot<=1):
L,M,Nbase=('페이지',1,None)
else:
L,M,Nbase=('게시판', tot if tot is not None else 0, None)
# N (없음이면 skip)
Nv='없음' if Nbase=='없음' else '어문'
if Nbase!='없음':
try:
pg.goto(fixdom(u),timeout=25000,wait_until='domcontentloaded'); pg.wait_for_timeout(700); pg.mouse.wheel(0,1200); pg.wait_for_timeout(250)
base=set(x for x in pg.evaluate(JS) if not UIPAT.search(x))
lh=pg.content(); bids=list(dict.fromkeys(re.findall(r'bIdx=(\d+)',lh)))[:3]
found=False
for b in bids:
pg.goto(fixdom(u)+'&state=view&bIdx='+b,timeout=25000,wait_until='domcontentloaded'); pg.wait_for_timeout(600); pg.mouse.wheel(0,1500); pg.wait_for_timeout(250)
det=[x for x in pg.evaluate(JS) if not UIPAT.search(x)]
extra=[x for x in det if x not in base]
if extra: found=True; break
Nv='어문,이미지' if found else '어문'
except Exception: Nv='어문'
plan[r]=(L,M,Nv,lab)
time.sleep(0.02)
print('판정 완료. 변경 미리보기:')
chg=0
for r in rows:
L,M,Nv,lab=plan[r]
cur=(ws.cell(r,12).value,ws.cell(r,13).value,str(ws.cell(r,14).value or ''))
if (L,M,Nv)!=cur:
chg+=1
if chg<=40: print(' r%d [%s] %s -> L=%s M=%s N=%s'%(r,lab,cur,L,M,Nv))
print('변경 %d'%chg)
import json
json.dump({str(r):plan[r] for r in rows},open(os.path.join(DIR,'_gugak_radio_lmn.json'),'w',encoding='utf-8'),ensure_ascii=False)
if not APPLY: print('DRY'); sys.exit(0)
mt=os.path.getmtime(xp); wb=openpyxl.load_workbook(xp); ws=wb.active
n=0
for r in rows:
if ws.cell(r,2).value is None: continue
L,M,Nv,lab=plan[r]
if ws.cell(r,12).value!=L: ws.cell(r,12).value=L; ws.cell(r,12).fill=BLUE; n+=1
if ws.cell(r,13).value!=M: ws.cell(r,13).value=M; ws.cell(r,13).fill=BLUE
if str(ws.cell(r,14).value or '')!=Nv: ws.cell(r,14).value=Nv; ws.cell(r,14).fill=BLUE
try:
if os.path.getmtime(xp)==mt:
shutil.copy(xp, os.path.join(d,'_backup',os.path.basename(xp).replace('.xlsx','_backup_radioLMN전.xlsx'))); wb.save(xp); print('saved 변경셀반영')
else: print('ABORT(변경됨)')
except PermissionError: print('LOCKED')