DB_JOB/작업파일/_스크립트/_vendor_probe.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

70 lines
3.1 KiB
Python

# -*- coding: utf-8 -*-
"""벤더 콘텐츠탭 셀렉터 조사: 샘플 페이지에서 탭류 컨테이너를 위치(부모 컨텍스트)와 함께 덤프."""
import openpyxl, requests, sys, re
from bs4 import BeautifulSoup
from urllib.parse import urljoin, urlparse
from concurrent.futures import ThreadPoolExecutor, as_completed
from collections import Counter
import urllib3
urllib3.disable_warnings()
sys.stdout.reconfigure(encoding='utf-8')
UA={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'}
NAV_ANCESTORS=('header','gnb','lnb','snb','nav','footer','top','aside','menu_wrap','allmenu','sitemap')
TABISH=re.compile(r'(tab|basic_tab|slave|grap|deth|nav_cont|intab)', re.I)
def is_in_nav(el):
p=el
for _ in range(8):
p=p.parent
if p is None: break
idc=(p.get('id') or '')+' '+' '.join(p.get('class') or [])
idc=idc.lower()
if any(k in idc for k in NAV_ANCESTORS): return True
return False
def main():
xlsx, n = sys.argv[1], int(sys.argv[2]) if len(sys.argv)>2 else 30
wb=openpyxl.load_workbook(xlsx); ws=wb.active
urls=[]
for r in range(3, ws.max_row+1):
c=ws.cell(r,11); L=ws.cell(r,12).value
u=c.hyperlink.target if c.hyperlink else (c.value if isinstance(c.value,str) and c.value.startswith('http') else None)
if u and L in ('페이지','게시판'): urls.append(u)
dom=Counter(urlparse(u).netloc.replace('www.','') for u in urls).most_common(1)[0][0]
urls=[u for u in urls if dom in urlparse(u).netloc]
seen=set(); samp=[]
for u in urls:
k=u.split('?')[0]
if k in seen: continue
seen.add(k); samp.append(u)
if len(samp)>=n: break
sess=requests.Session(); sess.headers.update(UA)
def fetch(u):
try:
rr=sess.get(u,timeout=20,verify=False); rr.encoding=rr.apparent_encoding or 'utf-8'; return u, rr.text
except: return u, None
sig=Counter()
with ThreadPoolExecutor(max_workers=12) as ex:
for fu in as_completed([ex.submit(fetch,u) for u in samp]):
u, html=fu.result()
if not html: continue
soup=BeautifulSoup(html,'html.parser')
for el in soup.find_all(['ul','div']):
idc=(el.get('id') or '')+' '+' '.join(el.get('class') or [])
if not TABISH.search(idc): continue
lis=[li for li in el.find_all('li') if li.find('a')]
if len(lis)<2: continue
anchors=[li.find('a') for li in lis]
hrefs=[a.get('href','') for a in anchors]
anchor_only=all(h.strip().startswith('#') or not h.strip() for h in hrefs)
kind='인페이지#' if anchor_only else '페이지/게시판링크'
where='NAV' if is_in_nav(el) else 'CONTENT'
tag=el.name
cls=re.sub(r'\d+','N','.'.join(el.get('class') or []) or ('#'+ (el.get('id') or '')))
sig[f"{where:7} {tag}.{cls[:24]:24} li={len(lis):>2} {kind}"]+=1
print(f'=== {xlsx.split(chr(92))[-1]} (도메인 {dom}, 샘플 {len(samp)}) ===')
for s,c in sig.most_common(25):
print(f' x{c:>2} {s}')
if __name__=='__main__': main()