import os import re import time import requests import openpyxl from bs4 import BeautifulSoup from urllib.parse import urljoin # ------------------------------------------------------------------------- # [설정 항목] # ------------------------------------------------------------------------- DOMAIN = "https://www.moel.go.kr/" # [필독] 현재 사용 중이신 원본 엑셀 파일명을 정확히 적어주세요. INPUT_EXCEL_FILE = r"D:\01.프로젝트\DB수집\고용노동부\고용노동부_사이트맵_r2.xlsx" OUTPUT_EXCEL_FILE = r"D:\01.프로젝트\DB수집\고용노동부\고용노동부_사이트맵_r3.xlsx" # 결과가 저장될 파일명 # ------------------------------------------------------------------------- # [헬퍼 함수] 공공누리 라이선스 유형 추출 # ------------------------------------------------------------------------- def extract_license_type(href): if not href: return None if 'www.kogl.or.kr/info/licenseType' in href: try: start_idx = href.find('licenseType') + len('licenseType') num = href[start_idx] if num.isdigit(): return f"{num}유형" except Exception: pass return None def find_kogl_license(soup): for a_tag in soup.find_all('a', href=True): href = a_tag['href'] license_type = extract_license_type(href) if license_type: return license_type return None # ------------------------------------------------------------------------- # [메인 로직] # ------------------------------------------------------------------------- def main(): if not os.path.exists(INPUT_EXCEL_FILE): print(f"[오류] '{INPUT_EXCEL_FILE}' 파일이 해당 경로에 존재하지 않습니다.") return # 기존 엑셀 파일 로드 wb = openpyxl.load_workbook(INPUT_EXCEL_FILE) ws = wb.active # 활성화된 시트 선택 (필요시 ws = wb['시트명'] 사용) headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' } # K열(11번째 열), 3번째 행부터 마지막 행까지 순회 # openpyxl에서 K열은 11번 열입니다. start_row = 3 max_row = ws.max_row print(f"[*] 엑셀 데이터를 로드했습니다. (3행부터 {max_row}행까지 탐색 시작)") for row in range(start_row, max_row + 1): url_cell_value = ws.cell(row=row, column=11).value # K열 데이터 추출 # URL 주소가 비어있거나 문자열이 아니면 패스 if not url_cell_value or not str(url_cell_value).strip().startswith("http"): continue url = str(url_cell_value).strip() print(f"\n[{row}행 작업 시작] {url}") # 타 도메인(예: safetyreport.go.kr, ifine.moel.go.kr) 대응용 도메인 추출 # 다른 도메인의 경우에도 해당 도메인 기준으로 절대경로 결합이 가능하도록 처리 current_domain = DOMAIN if "ifine.moel.go.kr" in url: current_domain = "https://ifine.moel.go.kr/" elif "safetyreport.go.kr" in url: current_domain = "https://www.safetyreport.go.kr/" try: res = requests.get(url, headers=headers, timeout=10) if res.status_code != 200: print(f"-> 접근 실패 (상태코드: {res.status_code})") ws.cell(row=row, column=15, value="접근 실패") # O열(판별)에 에러 기록 continue soup = BeautifulSoup(res.text, 'html.parser') # 1. 게시판 판별 및 건수(수량) 추출 page_p = soup.find('p', class_='page') total_span = page_p.find('span', class_='total') if page_p else None is_board = False total_count = 0 if total_span: is_board = True b_tag = total_span.find('b') count_text = b_tag.get_text() if b_tag else total_span.get_text() count_digits = re.sub(r'[^0-9]', '', count_text) if count_digits: total_count = int(count_digits) board_type = "게시판" if is_board else "페이지" print(f" - 판별: {board_type} / 수량: {total_count if is_board else '-'}") license_found = None mark_location = "" # 2. 1차 탐색 (
내부 영역 탐색) contents_div = soup.find('div', id='contents') search_area = contents_div if contents_div else soup list_license = find_kogl_license(search_area) if list_license: license_found = list_license mark_location = "게시판" print(f" => [목록 마크 발견] 유형: {license_found} (상세 skip)") elif is_board: # 목록에 없으면 상세 글 최대 5개 추출 후 탐색 print(" - 목록 내 마크 없음 -> 상세 글 5개 탐색 진행") table = search_area.find('table', class_='tstyle_list') detail_links = [] if table: a_tags = table.select('td.txt_left strong.b_tit a') for a in a_tags[:5]: href = a.get('href', '') if href: detail_links.append(urljoin(current_domain, href)) # 대체 패턴 검색 (일반 링크 파싱) if not detail_links: for a in search_area.find_all('a', href=True): href = a['href'] if 'View.do' in href or 'view.do' in href or 'seqRepeat=' in href: full_url = urljoin(current_domain, href) if full_url not in detail_links: detail_links.append(full_url) if len(detail_links) >= 5: break # 상세 페이지 탐색 for idx, detail_url in enumerate(detail_links, start=1): try: time.sleep(0.4) detail_res = requests.get(detail_url, headers=headers, timeout=7) if detail_res.status_code == 200: d_soup = BeautifulSoup(detail_res.text, 'html.parser') d_contents = d_soup.find('div', id='contents') d_search_area = d_contents if d_contents else d_soup detail_license = find_kogl_license(d_search_area) if detail_license: license_found = detail_license mark_location = "게시물" print(f" > 상세 ({idx}/5) 마크 발견: {license_found}") break except Exception: pass # 3. 데이터 매핑하여 기존 셀에 값 쓰기 # M열 = 13번째 열, O열 = 15번째 열, P열 = 16번째 열, Q열 = 17번째 열 ws.cell(row=row, column=13, value=total_count if is_board else "") # M열: 수량 ws.cell(row=row, column=15, value=board_type) # O열: 판별 ws.cell(row=row, column=16, value=mark_location) # P열: 마크 위치 ws.cell(row=row, column=17, value=license_found if license_found else "") # Q열: 유형 except Exception as e: print(f" [Error] {row}행 처리 중 에러 발생: {e}") ws.cell(row=row, column=15, value="에러 발생") # 변경 내용 저장 wb.save(OUTPUT_EXCEL_FILE) print(f"\n[작업 완료] 모든 결과가 '{OUTPUT_EXCEL_FILE}'에 덮어쓰기 완료되었습니다.") if __name__ == "__main__": main()