공공기관2 작업 중. _temp 몽타주(재생성가능)는 제외. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
68 lines
2.9 KiB
Python
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('&', '&')
|
|
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('&', '&')
|
|
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))
|