공공기관2 작업 중. _temp 몽타주(재생성가능)는 제외. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
48 lines
3.2 KiB
Python
48 lines
3.2 KiB
Python
# -*- coding: utf-8 -*-
|
||
# 게시판 후보 M(글수) 추출 + 보드확정(리스트행/날짜). 서브사이트홈 false-board 강등. 공공누리 푸터 재확인.
|
||
import json, io, sys, re, time
|
||
from playwright.sync_api import sync_playwright
|
||
sys.stdout=io.TextIOWrapper(sys.stdout.buffer,encoding='utf-8')
|
||
d=json.load(open('_cy4.json',encoding='utf-8'))
|
||
boards={rs:v for rs,v in d.items() if v.get('L')=='게시판'}
|
||
print('게시판 후보',len(boards),flush=True)
|
||
JS=r'''()=>{
|
||
const t=document.body?document.body.innerText:'';
|
||
const tot=(t.match(/총\s*게시물\s*[::]?\s*([\d,]+)/)||t.match(/총\s*([\d,]+)\s*건/)||t.match(/게시물\s*수\s*[::]?\s*([\d,]+)/)||t.match(/Total\s*[::]?\s*([\d,]+)/i)||t.match(/전체\s*[::]?\s*([\d,]+)/));
|
||
// 리스트 행: 번호+날짜 패턴
|
||
let rowsWithDate=0, maxno=0;
|
||
const main=document.querySelector('#contents,.contents,.sub_contents,#container,main')||document.body;
|
||
main.querySelectorAll('table tbody tr, ul li, .board_list li').forEach(tr=>{
|
||
const tx=tr.innerText||'';
|
||
if(/20\d\d[-.\/]\s?\d\d?[-.\/]\s?\d\d?/.test(tx)){ rowsWithDate++; const m=tx.match(/^\s*(\d{1,6})/); if(m){const n=parseInt(m[1]); if(n>maxno)maxno=n;} }
|
||
});
|
||
// 공공누리 푸터/본문
|
||
function kogl(root){const imgs=[...root.querySelectorAll('img')].filter(im=>/opentype0?(\d)/i.test(im.getAttribute('src')||''));const ty=new Set();let link=false;for(const im of imgs){const m=/opentype0?(\d)/i.exec(im.getAttribute('src')||'');if(m)ty.add(parseInt(m[1]));for(let n=im;n;n=n.parentElement){if(n.tagName==='A'&&n.getAttribute('href')&&n.getAttribute('href')!=='#'){link=true;break;}}}return{types:[...ty].sort(),link};}
|
||
const k=kogl(main);
|
||
const av=[...main.querySelectorAll('a')].filter(a=>/selectBoardArticle|nttId=|articleNo=|artclView/i.test(a.href||'')).length;
|
||
return {tot:tot?parseInt(tot[1].replace(/,/g,'')):null, rowsWithDate, maxno, av, kogl:k};
|
||
}'''
|
||
def nav(pg,u):
|
||
for _ in range(2):
|
||
try: pg.goto(u,wait_until='domcontentloaded',timeout=22000); pg.wait_for_timeout(1500); return True
|
||
except Exception: time.sleep(1)
|
||
return False
|
||
out={}
|
||
with sync_playwright() as p:
|
||
b=p.chromium.launch(); pg=b.new_page(viewport={'width':1300,'height':2600}); pg.set_default_timeout(22000)
|
||
for rs,v in sorted(boards.items(),key=lambda x:int(x[0])):
|
||
u=v['u']; r={'lab':v['lab']}
|
||
try:
|
||
if nav(pg,u):
|
||
e=pg.evaluate(JS)
|
||
M = e['tot'] if e['tot'] is not None else (e['maxno'] if e['maxno']>0 else (e['rowsWithDate'] if e['rowsWithDate']>0 else 0))
|
||
isboard = e['rowsWithDate']>=1 or e['av']>=1 or (e['tot'] is not None)
|
||
r.update(M=M, isboard=isboard, rwd=e['rowsWithDate'], av=e['av'], tot=e['tot'], maxno=e['maxno'], kogl=e['kogl'])
|
||
else: r.update(M=0,isboard=True,err='nav')
|
||
except Exception as ex: r.update(M=0,isboard=True,err=str(ex)[:30])
|
||
out[rs]=r
|
||
flag='' if r.get('isboard') else ' <<<NOT-BOARD(페이지강등)'
|
||
print('r%s %-18s M=%s rwd=%s av=%s tot=%s kogl=%s%s'%(rs,v['lab'][:18],r.get('M'),r.get('rwd'),r.get('av'),r.get('tot'),r.get('kogl',{}).get('types'),flag),flush=True)
|
||
b.close()
|
||
json.dump(out,open('_cy4_board.json','w',encoding='utf-8'),ensure_ascii=False)
|