DB_JOB/_스크립트/_probe_jeonbuk4.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

86 lines
4.0 KiB
Python

"""4차: 부안/완주/군산/순창 메뉴 소스 확정."""
import re, warnings
from urllib.parse import urljoin
import requests
from bs4 import BeautifulSoup
warnings.filterwarnings('ignore')
UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
def sess():
s = requests.Session(); s.headers.update({'User-Agent': UA}); return s
def fetch(s, url, t=20):
r = s.get(url, timeout=t, verify=False, allow_redirects=True)
meta = re.search(rb'<meta[^>]*charset=["\']?\s*([\w-]+)', r.content[:4096], re.I)
r.encoding = meta.group(1).decode('ascii','ignore') if meta else r.apparent_encoding
return r
S = sess()
def dump_menu_divs(soup, label):
print(f'\n--- {label}: class에 menu/gnb/sitemap/allmenu 포함 div·nav·ul (직계 a 텍스트) ---')
for el in soup.find_all(['div','nav','ul']):
cls = ' '.join(el.get('class', []))
idv = el.get('id','')
if re.search(r'menu|gnb|sitemap|site_map|allmenu|lnb|depth', cls + ' ' + idv, re.I):
n_a = len(el.find_all('a'))
n_li = len(el.find_all('li'))
if n_a >= 15: # 메가메뉴 후보
print(f' <{el.name} id="{idv}" class="{cls}"> a={n_a} li={n_li}')
# 부안: 사이트맵 menuCd 추정 — index의 모든 menuCd 중 *07*(정보공개류) 상위 노드 시도
print('=== 부안군 ===')
r = fetch(S, 'https://www.buan.go.kr/index.buan?contentsSid=1')
soup = BeautifulSoup(r.text, 'html.parser')
dump_menu_divs(soup, '부안 index')
# 누리집지도/사이트맵 후보 menuCd 시도
for cd in ['DOM_000000107003000000','DOM_000000108003000000','DOM_000000107002000000',
'DOM_000000106002000000','DOM_000000109002000000']:
try:
rr = fetch(S, f'https://www.buan.go.kr/index.buan?menuCd={cd}', t=10)
ss = BeautifulSoup(rr.text, 'html.parser')
has = bool(ss.select_one('div.sitemap'))
ttl = (ss.title.get_text().strip()[:30] if ss.title else '')
print(f' {cd}: div.sitemap={has} title={ttl!r}')
except Exception as e:
print(f' {cd}: ERR {type(e).__name__}')
# 완주: index 메가메뉴 + contentUid 사이트맵 후보
print('\n=== 완주군 ===')
r = fetch(S, 'https://www.wanju.go.kr/index.9is')
soup = BeautifulSoup(r.text, 'html.parser')
dump_menu_divs(soup, '완주 index')
for a in soup.find_all('a'):
t = (a.get_text() or '').strip()
if re.search(r'누리집|사이트맵|전체메뉴|지도', t):
print(' 완주 a:', repr(t[:25]), '| href=', (a.get('href') or '')[:100], '| onclick=', (a.get('onclick') or '')[:90])
# 군산: allmenubox 전체 구조(탭 포함)
print('\n=== 군산시 ===')
r = fetch(S, 'https://www.gunsan.go.kr/main')
soup = BeautifulSoup(r.text, 'html.parser')
dump_menu_divs(soup, '군산 index')
box = soup.select_one('div.allmenubox') or soup.select_one('div.allmw')
if box:
# 탭/카테고리 구조 — 직계 자식 요약
print(' allmenubox 하위 ul/div (a수):')
for el in box.find_all(['ul','div'], recursive=True):
cls = ' '.join(el.get('class', []))
n_a = len(el.find_all('a', recursive=False))
if n_a >= 5:
print(f' <{el.name} class="{cls}"> 직계a={n_a} 첫a={el.find("a").get_text().strip()[:15]!r}')
# 순창: HTML 내 sitemap/menu json/ajax 흔적
print('\n=== 순창군 ===')
r = fetch(S, 'https://www.sunchang.go.kr/')
html = r.text
soup = BeautifulSoup(html, 'html.parser')
dump_menu_divs(soup, '순창 index')
print(' html 내 sitemap/menu ajax url 흔적:')
for m in set(re.findall(r'["\']([^"\']*(?:sitemap|menu)[^"\']*\.(?:do|json|html|jsp))["\']', html, re.I)):
print(' ', m[:100])
# 순창 gnb_list가 ajax라면, 흔한 e-Gov 전체메뉴 경로 시도
for guess in ['/site/main/menu/sitemap','/kr/sitemap','/sitemap.do','/main/sitemap']:
try:
rr = fetch(S, urljoin('https://www.sunchang.go.kr', guess), t=10)
print(f' {guess} -> {rr.status_code}')
except Exception as e:
print(f' {guess} -> ERR')