DB_JOB/작업파일/완료/광역_사이트맵/전북특별자치도/14.진안군/_nshot2.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

68 lines
2.9 KiB
Python

# -*- coding: utf-8 -*-
"""진안 엑셀행 57~끝 본문 렌더 스크린샷(이미지 검출용). 페이지=#sub_contents/게시판=첫글. _nshots2/"""
import glob, os, re, json, urllib.request
from collections import Counter
import openpyxl
from playwright.sync_api import sync_playwright
DIR = os.path.dirname(__file__)
SHOT = os.path.join(DIR, '_nshots2')
os.makedirs(SHOT, exist_ok=True)
HDR = {'User-Agent': 'Mozilla/5.0'}
def get(u):
try:
return urllib.request.urlopen(urllib.request.Request(u.replace(' ', '%20'), headers=HDR), timeout=20).read().decode('utf-8', 'replace')
except Exception:
return ''
t = glob.glob(os.path.join(DIR, '*.xlsx'))
t = [p for p in t if 'backup' not in p and not os.path.basename(p).startswith(('~$', '_'))][0]
ws = openpyxl.load_workbook(t).active
targets = []
for r in range(57, ws.max_row + 1): # 엑셀행 57부터
L = ws.cell(r, 12).value
if L in ('페이지', '게시판'):
targets.append({'r': r, 'L': L, 'M': ws.cell(r, 13).value, 'N': str(ws.cell(r, 14).value or ''),
'lab': ws.cell(r, 7).value or ws.cell(r, 6).value or ws.cell(r, 5).value or '', 'K': str(ws.cell(r, 11).value or '')})
def first_post(k):
h = get(k).replace('&amp;', '&')
menu = re.search(r'menuCd=([A-Z0-9_]+)', k)
menu = menu.group(1) if menu else ''
vb = [b for b in re.findall(r'view\.jinan\?[^"\']*?boardId=([A-Z0-9_]+)[^"\']*?dataSid=', h) if b != 'BBS_0000157']
if not vb:
return None
bid = Counter(vb).most_common(1)[0][0]
lh = get(f'http://www.jinan.go.kr/board/list.jinan?boardId={bid}&menuCd={menu}&paging=ok&startPage=1').replace('&amp;', '&')
vs = [v for v in re.findall(r'view\.jinan\?([^"\']+)', lh) if f'boardId={bid}' in v and 'dataSid=' in v]
return ('http://www.jinan.go.kr/board/view.jinan?' + vs[0].replace(' ', '%20')) if vs else None
with sync_playwright() as pw:
br = pw.chromium.launch()
pg = br.new_page(viewport={'width': 1100, 'height': 1500})
for i, tg in enumerate(targets):
out = os.path.join(SHOT, f"r{tg['r']}.png")
if os.path.exists(out):
continue
url = tg['K']
if tg['L'] == '게시판' and tg['M'] not in (0, None):
pu = first_post(tg['K'])
if pu:
url = pu
try:
pg.goto(url, timeout=25000, wait_until='domcontentloaded')
pg.wait_for_timeout(1100)
el = None
for sel in ['#sub_contents', '#contents']:
el = pg.query_selector(sel)
if el:
break
(el or pg).screenshot(path=out)
except Exception as e:
print('ERR', tg['r'], str(e)[:50], flush=True)
if (i + 1) % 30 == 0:
print(f'... {i+1}/{len(targets)}', flush=True)
br.close()
json.dump(targets, open(os.path.join(DIR, '_ntargets2.json'), 'w', encoding='utf-8'), ensure_ascii=False, indent=0)
print('DONE', len(targets))