# -*- coding: utf-8 -*- # 충북 범용 공공누리(O) 본문영역 재검출: python _cb_kogl.py <엑셀> # 본문 컨테이너(#contents 등) 안의 img_opentype0N 만 인정(푸터 전역마크 제외). 게시판은 상세글 확인. import openpyxl, sys, io, re, ssl, time, urllib.request from bs4 import BeautifulSoup from concurrent.futures import ThreadPoolExecutor sys.stdout=io.TextIOWrapper(sys.stdout.buffer,encoding='utf-8') F=sys.argv[1]; HOST=sys.argv[2] ctx=ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE def get(u): for _ in range(2): try: req=urllib.request.Request(u,headers={'User-Agent':'Mozilla/5.0'}) return urllib.request.urlopen(req,timeout=20,context=ctx).read().decode('utf-8','ignore') except Exception: time.sleep(0.5) return '' CONTENT_SEL='#contents,.contents,#content,.content,.sub_content,.sub_contents,.contents_in,.bbs_view,.board_view,.view_con,.cont_area' def opentypes_in_content(html): s=BeautifulSoup(html,'html.parser') cont=s.select_one(CONTENT_SEL) area=cont if cont else s # 본문영역 내 opentype 이미지 found=set() for img in area.find_all('img'): src=(img.get('src') or '')+' '+(img.get('alt') or '') m=re.search(r'opentype0?(\d)',src) if m: found.add(int(m.group(1))) return sorted(found) wb=openpyxl.load_workbook(F); ws=wb.active def detail_url(html): s=BeautifulSoup(html,'html.parser') for a in s.find_all('a'): href=a.get('href') or '' if re.search(r'BbsNttView|addBbsNttView|nttNo=|nttId=|BoardArticle|selectBoardArticle',href): if href.startswith('http'): return href if href.startswith('/'): return 'https://'+HOST+href return None def work(r): L=ws.cell(r,12).value; url=ws.cell(r,11).value if L not in ('페이지','게시판') or not str(url or '').startswith('http'): return (r,None) h=get(url) if not h: return (r,None) if L=='게시판': # 상세글 최대 3개 확인 types=set(opentypes_in_content(h)) du=detail_url(h); n=0 while du and n<3: dh=get(du); types|=set(opentypes_in_content(dh)) nx=detail_url(dh); du=nx if nx and nx!=du else None; n+=1 if types: break return (r,sorted(types)) else: return (r,opentypes_in_content(h)) rows=[r for r in range(3,ws.max_row+1) if ws.cell(r,12).value in('페이지','게시판')] print('O검출 대상',len(rows),flush=True) results={} with ThreadPoolExecutor(max_workers=8) as ex: for r,t in ex.map(work,rows): results[r]=t chg=0 for r,t in results.items(): old=ws.cell(r,15).value new=','.join('%d유형'%x for x in t) if t else '미부착' if new!=old: ws.cell(r,15).value=new; chg+=1 wb.save(F) att=sum(1 for r in results if results[r]) print('O 본문부착 %d행 | 변경 %d'%(att,chg))