Python으로 뉴스 크롤링부터 이메일 전송까지 완전 자동화 해보기
2025. 7. 7. 14:51
매일 아침, 보안 이슈를 빠르게 확인하고 싶어서 직접 자동화 시스템을 만들어봤습니다.
보안뉴스 사이트의 #보안사고 기사만 크롤링해 정리하고, 이를 매일 아침 이메일로 자동 발송하는 스크립트를 제작했습니다.
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. 설정 탭
- 혹시 지정한 시간에 컴퓨터가 꺼져있을 경우를 대비해, 표시한 옵션도 체크해준다.




