import sys, io, re, ssl, urllib.request sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') ctx = ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE BASE='https://www.jangsu.go.kr/index.jangsu?menuCd=' def fetch(cd, tries=4): for i in range(tries): try: return urllib.request.urlopen(urllib.request.Request(BASE+cd, headers={'User-Agent':'Mozilla/5.0'}), context=ctx, timeout=45).read().decode('utf-8','replace') except Exception as e: last=e raise last home=fetch('') # index.jangsu # 대분류 107/108/303 라벨 — 홈페이지 어디든 그 menuCd 링크 텍스트 for d in ['107','108','303']: labs=set() for m in re.finditer(r'menuCd=DOM_000000'+d+r'(\d{9})"[^>]*>(?:]*>)?\s*([^<]{1,25})', home): sub=m.group(1); lab=m.group(2).strip() if sub=='000000000' and lab: labs.add(('대',lab)) elif sub[3:]=='000000' and lab: labs.add(('중'+sub[:3],lab)) print(f'대{d} 라벨후보:', list(labs)[:12]) # 108 페이지 실제 콘텐츠? + 에러4건 재확인 print('--- 페이지 실체 확인 ---') for nm,cd in [('108 기획조정실','108001001000'),('107 개인정보','107003001000'),('303 공약','303007001000'), ('민원실안내(에러)','101001001000'),('가족관계등록(에러)','101001011000')]: try: h=fetch(cd) title=re.search(r'([^<|]+)',h) m=re.search(r'id="contents"(.*?)(?:<footer|id="footer)',h,re.S) txt=re.sub(r'\s+',' ',re.sub(r'<[^>]+>',' ',re.sub(r'<script.*?</script>','',m.group(1),flags=re.S))).strip() if m else '' bbs='bbs_list' in (m.group(1) if m else '') tt=title.group(1).strip() if title else '?' print(' ['+nm+'] title='+repr(tt)+' bbs='+str(bbs)+' txt[:90]='+repr(txt[:90])) except Exception as e: print(f' [{nm}] ERR {e}')