매일 아침, 보안 이슈를 빠르게 확인하고 싶어서 직접 자동화 시스템을 만들어봤습니다.

보안뉴스 사이트의 #보안사고 기사만 크롤링해 정리하고, 이를 매일 아침 이메일로 자동 발송하는 스크립트를 제작했습니다.

 

Python으로 크롤링 및 이메일 발송 코드를 작성했고,

Windows 작업 스케줄러를 이용해 정해진 시간에 자동으로 실행되도록 설정했습니다.

 

이메일로 받을 수 있는 결과물


덕분에 이제 매일 출근 전에 오늘의 보안사고 뉴스를 정리한 메일을 바로 받아볼 수 있어서

일일 이슈 체크가 한결 간편해졌습니다.

 


 

news_crawling.py 

- SAVE_TO_EXEL 변수 값을 조정하면 엑셀 저장 여부도 설정할 수 있습니다.

# news_crawling.py

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import pandas as pd
import datetime
from openpyxl import load_workbook
from openpyxl.styles import Alignment
from openpyxl.utils import get_column_letter
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText


# 크롬드라이버 설정 (경로 확인 필요)
service = Service('./chromedriver.exe')
options = webdriver.ChromeOptions()
options.add_argument('--headless')  # 브라우저 창 없이 실행
options.add_argument('--disable-gpu')
driver = webdriver.Chrome(service=service, options=options)

# 보안뉴스 사건사고 탭 URL
url = 'https://www.boannews.com/search/news_hash.asp?find=%BB%E7%B0%C7%BB%E7%B0%ED'
driver.get(url)

# 뉴스 리스트 로딩 대기 시간 15초
try:
    news_items = WebDriverWait(driver, 15).until(
        EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'div#news_area div.news_list'))
    )
except Exception as e:
    print("뉴스 리스트를 찾을 수 없습니다.", e)
    driver.quit()
    exit()

# 데이터 수집
data = []
for item in news_items:
    try:
        title = item.find_element(By.CSS_SELECTOR, 'span.news_txt').text.strip()
        link = item.find_element(By.TAG_NAME, 'a').get_attribute('href')
        summary = item.find_element(By.CSS_SELECTOR, 'a.news_content').text.strip()
        writer_date = item.find_element(By.CSS_SELECTOR, 'span.news_writer').text.strip()

        data.append({
            '제목': title,
            '요약': summary,
            '링크': link,
            '기자 & 날짜': writer_date
        })
    except Exception as e:
        print("뉴스 항목에서 데이터 추출 중 오류:", e)
        continue

driver.quit()

# dataframe으로 변환
df = pd.DataFrame(data)



# 오늘 날짜
today = datetime.datetime.today().strftime('%Y-%m-%d')

# 엑셀 저장 여부 설정 
# (True → 저장, False → 저장 안함)
SAVE_TO_EXCEL = False

# 엑셀 저장 (옵션값이 True일 때만)
if SAVE_TO_EXCEL:
    file_name = f"{today} 보안뉴스.xlsx"
    df.to_excel(file_name, index=False)

    # 엑셀 서식 설정
    wb = load_workbook(file_name)
    ws = wb.active

    # 셀 줄바꿈 및 정렬
    for row in ws.iter_rows(min_row=2, max_col=4):
        for cell in row:
            cell.alignment = Alignment(wrap_text=True, vertical='top')

    # 열 너비 설정
    column_widths = [20, 50, 60, 80]
    for i, width in enumerate(column_widths, 1):
        ws.column_dimensions[get_column_letter(i)].width = width

    # 행 높이 설정
    for row in range(2, ws.max_row + 1):
        ws.row_dimensions[row].height = 120

    wb.save(file_name)
    print("오늘의 보안뉴스를 엑셀 파일로 저장했습니다.")


# 이메일 설정
EMAIL_ADDRESS = '송신자 이메일 주소'
EMAIL_PASSWORD = '송신자의 구글 앱 비밀번호'  # 앱 비밀번호 (Google 2차 인증용)
RECEIVER_EMAIL = '수신자 이메일 주소'

# HTML 구성
html_content = f'''
<html>
<head>
  <style>
    body {{
      font-family: 'Arial', sans-serif;
      font-size: 14px;
      color: #333;
      margin: 20px;
    }}
    h2 {{
      color: #2c3e50;
    }}
    table {{
      border-collapse: collapse;
      width: 100%;
      margin-top: 20px;
    }}
    th, td {{
      border: 1px solid #ddd;
      padding: 10px;
      text-align: left;
      vertical-align: top;
    }}
    th {{
      background-color: #f2f2f2;
      color: #333;
    }}
    tr:nth-child(even) {{
      background-color: #fbfbfb;
    }}
    a {{
      color: #3498db;
      text-decoration: none;
    }}
    a:hover {{
      text-decoration: underline;
    }}
  </style>
</head>
<body>
  <h2>{today}의 보안사고 뉴스입니다.</h2>
  <table>
    <tr>
      <th>제목</th>
      <th>요약</th>
      <th>링크</th>
    </tr>
'''

# 테이블에 데이터 추가
for _, row in df.iterrows():
    html_content += f'''
    <tr>
      <td>{row['제목']}</td>
      <td>{row['요약']}</td>
      <td><a href="{row['링크']}" target="_blank">바로가기</a></td>
    </tr>
    '''

# HTML 마무리
html_content += '''
  </table>
</body>
</html>
'''

# 이메일 작성
msg = MIMEMultipart('alternative')
msg['Subject'] = f"{today} 보안뉴스 요약"
msg['From'] = EMAIL_ADDRESS
msg['To'] = RECEIVER_EMAIL

# 본문 HTML 삽입
part = MIMEText(html_content, 'html')
msg.attach(part)

# 메일 서버 연결 및 전송
with smtplib.SMTP('smtp.gmail.com', 587) as smtp:
    smtp.ehlo()
    smtp.starttls()
    smtp.login(EMAIL_ADDRESS, EMAIL_PASSWORD)
    smtp.send_message(msg)

print("메일 전송 완료")

 

 


 

작업 스케줄러 등록

1. 새 작업 만들기 클릭

 

2. 가장 높은 수준의 권한으로 실행 체크

 

 

3. 트리거 설정

 

 

4. 동작 설정

- 프로그램/스크립트 : python.exe 설치 경로 입력

- 인수 추가 : news_crawling.py 파일의 경로 입력

- 시작 위치 : news_crawling.py가 들어있는 폴더 경로 입력

 

(주의) 경로에 띄어쓰기나 한글이 포함되면 오류가 생길 수 있다.

 

5. 설정 탭

- 혹시 지정한 시간에 컴퓨터가 꺼져있을 경우를 대비해, 표시한 옵션도 체크해준다.