DB_JOB/_스크립트/_공공기관_lfix.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

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