공공기관2 작업 중. _temp 몽타주(재생성가능)는 제외. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
93 lines
4.0 KiB
Python
93 lines
4.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""공공기관 L 재분류 — '페이지'로 오분류된 게시판 교정(eGov ESF board_pager/list/권호 위젯 누락 보강).
|
|
대상: L=='페이지' 행만 재검. 게시판이면 L=게시판·M산출. 기존 게시판/사이트 불변.
|
|
사용: python _공공기관_lfix.py [기관명 ...]
|
|
"""
|
|
import sys, os, re, json, importlib.util, warnings
|
|
import openpyxl
|
|
warnings.filterwarnings('ignore')
|
|
spec = importlib.util.spec_from_file_location('p234', r'D:\01.프로젝트\DB수집\_스크립트\_공공기관_phase234.py')
|
|
P = importlib.util.module_from_spec(spec); spec.loader.exec_module(P)
|
|
specm = importlib.util.spec_from_file_location('mf', r'D:\01.프로젝트\DB수집\_스크립트\_공공기관_mfix.py')
|
|
MF = importlib.util.module_from_spec(specm); specm.loader.exec_module(MF)
|
|
OUTDIR = r'D:\01.프로젝트\DB수집\공공기관'
|
|
LOG = open(r'D:\01.프로젝트\DB수집\_스크립트\_lfix_result.txt', 'w', encoding='utf-8')
|
|
|
|
|
|
def say(s):
|
|
LOG.write(s + '\n'); LOG.flush()
|
|
|
|
|
|
def is_board(body):
|
|
"""강화 게시판 판별. 콘텐츠 스코프(get_body) 가정."""
|
|
# 1) 페이징 위젯(board_pager 포함)
|
|
if body.select('[class*=pager], [class*=paging], [class*=pagination], [class*=paginate]'):
|
|
# 단, 1페이지뿐인 빈 위젯 배제 위해 링크/번호 존재 확인은 생략(존재 자체가 게시판형)
|
|
return True, '페이징위젯'
|
|
# 2) 게시판 리스트 컨테이너
|
|
if body.select('[class*=board_list], [class*=bbs_list], [class*=gallery_list], [class*=photo_list], [class*=galleryList], table.bbs, [class*=board] table tbody tr'):
|
|
return True, '리스트컨테이너'
|
|
# 3) 발간물/정기간행물 권호 아카이브(select 또는 통권 다수)
|
|
if body.select('select[name*=vol], select[name*=issue], select[id*=vol], [class*=volume], [class*=kwon], [class*=issue_list]'):
|
|
return True, '권호아카이브'
|
|
txt = body.get_text(' ', strip=True)
|
|
if len(re.findall(r'통권\s*\d+\s*권', txt)) >= 3 or len(re.findall(r'제?\s*\d+\s*호', txt)) >= 4:
|
|
return True, '권호다수'
|
|
# 4) 총건수 텍스트
|
|
if P.TOTAL_PAT.search(txt) or re.search(r'(?:전체|총)\s*[:\-]?\s*\d[\d,]*\s*건', txt):
|
|
return True, '총건수'
|
|
# (list 링크다수 규칙은 부서소개 등 페이지 오탐이 많아 제외)
|
|
return False, ''
|
|
|
|
|
|
def run(name, sess):
|
|
xlsx = os.path.join(OUTDIR, f'{name}.xlsx')
|
|
wb = openpyxl.load_workbook(xlsx)
|
|
ws = wb.active
|
|
changed = 0
|
|
for r in range(3, ws.max_row + 1):
|
|
if ws.cell(r, 2).value is None:
|
|
break
|
|
if ws.cell(r, 12).value != '페이지':
|
|
continue
|
|
url = ws.cell(r, 11).value
|
|
if not url or not isinstance(url, str) or not url.startswith('http'):
|
|
continue
|
|
soup, final = P.fetch(sess, url)
|
|
if not soup:
|
|
continue
|
|
body = P.get_body(soup, P.BODY_SEL)
|
|
ok, why = is_board(body)
|
|
if not ok:
|
|
continue
|
|
# 게시판으로 승격 + M 산출
|
|
c, how = MF.board_count(body)
|
|
ws.cell(r, 12).value = '게시판'
|
|
ws.cell(r, 13).value = c if c > 0 else 0
|
|
changed += 1
|
|
say(f' {name} r{r} 페이지→게시판 M={c}({how}) [{why}] {ws.cell(r,5).value or ws.cell(r,4).value}')
|
|
wb.save(xlsx)
|
|
say(f'[{name}] 페이지→게시판 {changed}행')
|
|
return changed
|
|
|
|
|
|
def main():
|
|
probe = {r['name']: r for r in json.load(open(r'D:\01.프로젝트\DB수집\_스크립트\_공공기관_probe.json', encoding='utf-8'))}
|
|
order = sorted(probe.values(), key=lambda x: -int(x['num']))
|
|
only = sys.argv[1:]
|
|
if only:
|
|
order = [p for p in order if p['name'] in only or str(p['num']) in only]
|
|
sess = P.make_session()
|
|
tot = 0
|
|
for p in order:
|
|
try:
|
|
tot += run(p['name'], sess)
|
|
except Exception as e:
|
|
say(f"[{p['name']}] 실패: {e}")
|
|
say(f'=== L재분류 합계 {tot}행 페이지→게시판 ===')
|
|
LOG.close()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|