공공기관2 작업 중. _temp 몽타주(재생성가능)는 제외. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
85 lines
3.7 KiB
Python
85 lines
3.7 KiB
Python
"""전북 미해결 사이트 2차 정밀 탐색."""
|
|
import re, ssl, sys, warnings
|
|
from urllib.parse import urljoin, urlparse
|
|
import requests
|
|
from requests.adapters import HTTPAdapter
|
|
from urllib3.util.ssl_ import create_urllib3_context
|
|
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
|
|
|
|
# 사이트맵 링크를 못 찾은 사이트: 인덱스 HTML에서 sitemap/menuCd/전체메뉴 힌트 검색
|
|
NOLINK = {
|
|
'군산시': 'https://www.gunsan.go.kr/main',
|
|
'남원시': 'https://www.namwon.go.kr/index.do?menuUid=ff8080818e3beff0018e40e8f63e02d2',
|
|
'부안군': 'https://www.buan.go.kr/index.buan?contentsSid=1',
|
|
'완주군': 'https://www.wanju.go.kr/index.9is',
|
|
'임실군': 'https://www.imsil.go.kr/index.imsil',
|
|
'정읍시': 'https://www.jeongeup.go.kr/index.jeongeup',
|
|
}
|
|
|
|
def probe_links(name, url):
|
|
print(f'\n{"="*70}\n[{name}] {url}')
|
|
s = sess()
|
|
try:
|
|
r = fetch(s, url)
|
|
except Exception as e:
|
|
print(' fetch fail', e); return
|
|
base = f'{urlparse(r.url).scheme}://{urlparse(r.url).netloc}'
|
|
soup = BeautifulSoup(r.text, 'html.parser')
|
|
# sitemap/전체메뉴 텍스트나 href를 가진 a 전부
|
|
hits = []
|
|
for a in soup.find_all('a'):
|
|
txt = (a.get_text() or '').strip()
|
|
href = a.get('href','') or ''
|
|
oc = a.get('onclick','') or ''
|
|
blob = f'{txt}|{href}|{oc}'
|
|
if re.search(r'사이트맵|전체메뉴|sitemap|site_map|allmenu', blob, re.I):
|
|
hits.append((txt[:20], href[:90], oc[:90]))
|
|
for h in hits[:15]:
|
|
print(' a:', h)
|
|
# menuCd 패턴 가진 href 중 sitemap 후보 (DOM_...02000000 류)
|
|
cds = set(re.findall(r'menuCd=DOM_\d+', r.text))
|
|
print(' menuCd 샘플:', list(cds)[:10])
|
|
|
|
for n, u in NOLINK.items():
|
|
probe_links(n, u)
|
|
|
|
# ---- 구조 깊이 확인이 필요한 사이트들 ----
|
|
DEEP = {
|
|
'고창군': 'https://www.gochang.go.kr/index.gochang?menuCd=DOM_000000106006000000',
|
|
'익산시': 'https://www.iksan.go.kr/index.do?menuUid=ff80808199f0d11c019a041b8e35174a',
|
|
'전주시': 'https://www.jeonju.go.kr/index.9is?contentUid=ff8080818c7c2e8e018c7fd67b9a03b6',
|
|
'순창군': 'https://www.sunchang.go.kr/',
|
|
'진안군': 'https://www.jinan.go.kr/index.jinan?menuCd=DOM_000000110002000000',
|
|
}
|
|
|
|
def deep(name, url, sel):
|
|
print(f'\n{"#"*70}\n[{name}] DEEP {url} sel={sel}')
|
|
s = sess()
|
|
try:
|
|
r = fetch(s, url)
|
|
except Exception as e:
|
|
print(' fail', e); return
|
|
soup = BeautifulSoup(r.text, 'html.parser')
|
|
cont = soup.select_one(sel)
|
|
if not cont:
|
|
print(' 컨테이너 없음'); return
|
|
# 첫 블록 하나만 골라 li/a href까지 자세히
|
|
print(cont.prettify()[:2500])
|
|
|
|
deep('고창군 첫메뉴', 'https://www.gochang.go.kr/index.gochang?menuCd=DOM_000000106006000000', 'div.sitemap div.menu1')
|
|
deep('익산시 group수', 'https://www.iksan.go.kr/index.do?menuUid=ff80808199f0d11c019a041b8e35174a', 'div.sitemap_group')
|
|
deep('전주시', 'https://www.jeonju.go.kr/index.9is?contentUid=ff8080818c7c2e8e018c7fd67b9a03b6', 'div.sitemap_Warp')
|
|
deep('순창군 gnb', 'https://www.sunchang.go.kr/', 'div.sitemap_box ul.gnb_list')
|
|
deep('진안군 첫dl', 'https://www.jinan.go.kr/index.jinan?menuCd=DOM_000000110002000000', 'div.sitemap dl')
|