공공기관2 작업 중. _temp 몽타주(재생성가능)는 제외. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
85 lines
3.9 KiB
Python
85 lines
3.9 KiB
Python
# -*- coding: utf-8 -*-
|
||
# 프리랜서2 신규 기준 읽기전용 재감사 — 머신체크 가능 위반만.
|
||
import os, glob, io, sys, re
|
||
import openpyxl
|
||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||
|
||
BASE = r'D:\01.프로젝트\DB수집\작업파일'
|
||
N_OK = {'어문','이미지','영상','오디오','글꼴','3D','기타','없음'}
|
||
# 열: L=12 M=13 N=14 O=15 P=16 Q=17, S(비고)=19
|
||
def audit(path):
|
||
wb = openpyxl.load_workbook(path, read_only=True, data_only=True)
|
||
ws = wb.active
|
||
rows = [r for r in ws.iter_rows(min_row=3, values_only=True)]
|
||
res = {'rows':0,'P페이지':[], 'N위반':{}, '사이트오염':[], '게시판M0N':[], '로그인':[], '페이지M≠1':0}
|
||
for i,row in enumerate(rows, start=3):
|
||
def g(col): return row[col-1] if len(row)>=col else None
|
||
B=g(2)
|
||
if not isinstance(B,int): continue
|
||
res['rows']+=1
|
||
L=str(g(12) or '').strip(); M=g(13); N=str(g(14) or '').strip()
|
||
O=g(15); P=str(g(16) or '').strip(); Q=g(17); S=str(g(19) or '')
|
||
# P=페이지
|
||
if P=='페이지': res['P페이지'].append(i)
|
||
# N 8종 위반
|
||
if N and L!='사이트':
|
||
for tok in N.split(','):
|
||
tok=tok.strip()
|
||
if tok and tok not in N_OK:
|
||
res['N위반'].setdefault(tok,[]).append(i)
|
||
# 사이트 오염
|
||
if L=='사이트' and any(x not in (None,'') for x in (M,g(14),O,g(16),Q)):
|
||
res['사이트오염'].append(i)
|
||
# 게시판 M0 & N≠없음
|
||
if L=='게시판' and (M in (0,'0')) and N not in ('없음',''):
|
||
res['게시판M0N'].append(i)
|
||
# 페이지 M≠1 (인페이지탭 가능 → 참고)
|
||
if L=='페이지' and M not in (1,'1',None):
|
||
res['페이지M≠1']+=1
|
||
# 로그인 흔적
|
||
if re.search(r'로그인|본인인증', S):
|
||
res['로그인'].append(i)
|
||
wb.close()
|
||
return res
|
||
|
||
def collect():
|
||
files=[]
|
||
for p in glob.glob(os.path.join(BASE,'광역_사이트맵','*','*','*.xlsx')):
|
||
b=os.path.basename(p)
|
||
if 'backup' in b or b.startswith('_'): continue
|
||
files.append(p)
|
||
for p in glob.glob(os.path.join(BASE,'교육청_사이트맵','*','*.xlsx')):
|
||
b=os.path.basename(p)
|
||
if 'backup' in b or b.startswith('_'): continue
|
||
files.append(p)
|
||
return sorted(files)
|
||
|
||
def main():
|
||
files=collect()
|
||
print('감사 대상 파일:',len(files))
|
||
total={'P페이지':0,'N위반':0,'사이트오염':0,'게시판M0N':0,'로그인':0,'페이지M≠1':0}
|
||
badN_global={}
|
||
flagged=[]
|
||
for p in files:
|
||
nm=os.path.basename(p).replace('.xlsx','')
|
||
try: r=audit(p)
|
||
except Exception as e:
|
||
print('ERR',nm,e); continue
|
||
nP=len(r['P페이지']); nN=sum(len(v) for v in r['N위반'].values())
|
||
nC=len(r['사이트오염']); nM0=len(r['게시판M0N']); nLg=len(r['로그인']); nPM=r['페이지M≠1']
|
||
total['P페이지']+=nP; total['N위반']+=nN; total['사이트오염']+=nC
|
||
total['게시판M0N']+=nM0; total['로그인']+=nLg; total['페이지M≠1']+=nPM
|
||
for k,v in r['N위반'].items(): badN_global[k]=badN_global.get(k,0)+len(v)
|
||
if nP or nN or nC or nM0 or nLg:
|
||
flagged.append((nm,r['rows'],nP,nN,r['N위반'],nC,nM0,nLg,nPM))
|
||
print('\n=== 위반 있는 기관 ===')
|
||
print('%-22s %5s %6s %6s %-18s %5s %5s %5s'%('기관','행','P페이지','N위반','(N위반값)','사이트','M0N','로그인'))
|
||
for (nm,rows,nP,nN,badN,nC,nM0,nLg,nPM) in flagged:
|
||
bn=','.join('%s×%d'%(k,len(v)) for k,v in badN.items()) if badN else ''
|
||
print('%-22s %5d %6d %6d %-18s %5d %5d %5d'%(nm,rows,nP,nN,bn[:18],nC,nM0,nLg))
|
||
print('\n=== 합계 ===', total)
|
||
print('N위반 값 분포:', badN_global)
|
||
print('참고: 페이지M≠1 합계 %d (인페이지탭 정상 포함 가능)'%total['페이지M≠1'])
|
||
|
||
main()
|