DB_JOB/작업파일/완료_1-2주차/1주차(5.19~5.25)/과학기술정보통신부(완료)/수집하기.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

183 lines
7.3 KiB
Python

import os
import time
import re
import requests
from bs4 import BeautifulSoup
import openpyxl
def check_media_types(soup, content_area):
"""
본문 영역을 분석하여 8종 저작물 유형을 다중 판별하는 함수
"""
if not content_area:
return "없음"
types = []
# 1. 어문
text_content = content_area.get_text(strip=True)
if text_content:
types.append("어문")
# 2. 이미지
images = content_area.find_all('img')
has_bg_img = 'background-image' in str(content_area).lower()
if images or has_bg_img:
types.append("이미지")
# 3. 영상
video_tags = content_area.find_all(['video', 'iframe', 'embed', 'object'])
html_str = str(content_area).lower()
video_ext = re.search(r'\.(mp4|avi|mkv|wmv|mov|flv)\b', html_str)
if video_tags or 'youtube.com' in html_str or 'youtu.be' in html_str or video_ext:
types.append("영상")
# 4. 오디오
audio_tags = content_area.find_all('audio')
audio_ext = re.search(r'\.(mp3|wav|ogg|wma|m4a)\b', html_str)
if audio_tags or audio_ext:
types.append("오디오")
# 5. 글꼴
style_tags = soup.find_all('style')
has_font_face = any('@font-face' in s.text for s in style_tags)
font_ext = re.search(r'\.(ttf|woff|woff2|otf|eot)\b', html_str)
if has_font_face or font_ext:
types.append("글꼴")
# 6. 3D
canvas_tags = content_area.find_all('canvas')
three_d_ext = re.search(r'\.(obj|gltf|glb|fbx|3ds)\b', html_str)
if 'webgl' in html_str or canvas_tags or three_d_ext:
types.append("3D")
# 7. 기타
if not types:
doc_ext = re.search(r'\.(zip|pdf|hwp|docx|xlsx|pptx)\b', html_str)
if doc_ext:
types.append("기타")
if not types:
return "없음"
return ", ".join(types)
def fetch_page_soup(url, headers):
try:
time.sleep(1.2) # 차단 예방 딜레이
response = requests.get(url, headers=headers, timeout=10)
if response.status_code == 200:
return BeautifulSoup(response.content, 'html.parser')
except Exception as e:
print(f" [접속 패스] {url} -> {e}")
return None
def main():
file_path = r"C:\Users\hehih\ownCloud\알바\고용노동부\고용노동부_사이트맵_완료.xlsx"
# ★ 기존 파일은 건드리지 않고 _ai를 붙여 다른 파일로 저장하기 위한 경로 조립
dir_name = os.path.dirname(file_path)
base_name = os.path.basename(file_path)
file_title, ext = os.path.splitext(base_name)
save_file_path = os.path.join(dir_name, f"{file_title}_ai{ext}")
if not os.path.exists(file_path):
print(f"[오류] 원본 파일 경로를 확인해주세요: {file_path}")
return
print("원본 엑셀 파일을 안전하게 읽어오는 중입니다...")
wb = openpyxl.load_workbook(file_path)
sheet = wb.active
base_url = "https://www.moel.go.kr"
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'
}
col_url = 11 # K열 (주소)
col_type = 12 # L열 (게시판형태)
col_license = 14 # N열 (저작물 유형 수집 목적지)
max_row = sheet.max_row
print(f"{max_row}행 분석을 시작합니다. (4행부터 출발)")
print(f"결과는 새 파일로 분리 저장됩니다:\n-> {save_file_path}\n")
for row in range(4, max_row + 1):
cell_url = sheet.cell(row=row, column=col_url).value
cell_type = sheet.cell(row=row, column=col_type).value
if not cell_type or str(cell_type).strip() not in ['게시판', '페이지']:
continue
if not cell_url:
continue
main_url = str(cell_url).strip()
if main_url.startswith('/'):
main_url = base_url + main_url
elif not main_url.startswith('http'):
main_url = base_url + '/' + main_url
detected_types_list = []
# 게시판형 분석 (상위 5개 링크 스캔)
if str(cell_type).strip() == '게시판':
print(f"[{row}/{max_row}] 게시판 스캔 시작: {main_url}")
list_soup = fetch_page_soup(main_url, headers)
if list_soup:
board_list_div = list_soup.find('div', class_='board_list')
if board_list_div:
links = board_list_div.select('strong.b_tit a')
target_links = links[:5] # 최대 5개 제한 규칙
for a_tag in target_links:
href = a_tag.get('href', '').strip()
if not href:
continue
detail_url = href if href.startswith('http') else base_url + href
detail_soup = fetch_page_soup(detail_url, headers)
if detail_soup:
content_area = detail_soup.find('div', id='contents_body')
res_type = check_media_types(detail_soup, content_area if content_area else detail_soup)
if res_type != "없음":
detected_types_list.extend(res_type.split(", "))
# 페이지형 분석 (다이렉트 스캔)
elif str(cell_type).strip() == '페이지':
print(f"[{row}/{max_row}] 페이지형 스캔 시작: {main_url}")
page_soup = fetch_page_soup(main_url, headers)
if page_soup:
content_area = page_soup.find('div', id='contents')
res_type = check_media_types(page_soup, content_area if content_area else page_soup)
if res_type != "없음":
detected_types_list.extend(res_type.split(", "))
# 중복 제거 후 최종 N열 기록
if detected_types_list:
final_types = ", ".join(sorted(list(set(detected_types_list))))
else:
final_types = "없음"
sheet.cell(row=row, column=col_license).value = final_types
print(f" => [N열 기록 완료]: {final_types}")
# 5행마다 안전하게 새 파일 경로로 백업 저장 (원본 보호)
if row % 5 == 0:
try:
wb.save(save_file_path)
except PermissionError:
print(f"[경고] {os.path.basename(save_file_path)} 파일이 열려있어 중간 저장에 실패했습니다. 엑셀을 닫아주세요.")
try:
wb.save(save_file_path)
print("\n==================================================")
print("🎉 8종 저작물 유형 자동 분류 및 기입 완료!")
print(f"기존 파일은 완벽히 보존되었으며, 아래 파일로 새 저장되었습니다:\n-> {save_file_path}")
print("==================================================")
except PermissionError:
print(f"\n[오류] 최종 저장 실패! {os.path.basename(save_file_path)} 파일 창이 열려 있다면 닫고 다시 실행해 주세요.")
if __name__ == "__main__":
main()