혼공학습단/혼공파

[혼공파] Beautiful Soup & Flask 로 기상청 날씨 정보 훔치기

sunghoyaaa 2025. 2. 23. 23:00

혼자 공부하는 파이썬 (개정판)

이 게시글은 혼공학습단(혼공파) 13기의 6주차 과제를 포함하고 있습니다.

Flask와 BeautifulSoup 간단 소개 

Flask는 가벼운 웹 프레임워크로 간단한 웹 애플리케이션을 빠르게 개발할 수 있는 도구입니다.  

BeautifulSoup은 HTML/XML을 파싱하여 웹 크롤링을 쉽게 할 수 있도록 도와주는 라이브러리입니다. 

from flask import Flask
from urllib import request
from bs4 import BeautifulSoup

class WeatherScraper:
  """기상청 날씨 데이터를 가져와 처리하는 클래스"""

  def __init__(self, url: str):
    """생성자: 가져올 URL을 설정"""
    self.url = url
    self.soup = None

  def fetch_weather_data(self):
    """웹에서 데이터를 가져와 BeautifulSoup으로 분석"""
    response = request.urlopen(self.url)
    self.soup = BeautifulSoup(response, "html.parser")

  # 파일로 저장하는 이유는 디버그 용도
  # print()함수로 사용해서 확인하니까 너무 길어서 짤림...
  def save_to_file(self, filename: str = "result.html"):
    """파싱된 데이터를 파일로 저장"""
    if self.soup:
      with open(filename, "w", encoding="utf-8") as file:
        file.write(str(self.soup))

  def parse_weather(self) -> str:
    """HTML 문서 전체를 생성하여 반환"""

    if not self.soup:
      return "<p>날씨 데이터를 불러오지 못했습니다.</p>"

    output = """
    <!DOCTYPE html>
    <html lang="ko">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>[혼공파] - 6주차 과제</title>
      <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        h1 { color: darkblue; }
        h3 { color: darkred; }
        hr { border: 0; height: 1px; background: gray; margin: 10px 0; }
      </style>
    </head>
    <body>
      <h1>[혼공파] 6주차 마지막 과제</h1>
    """

    # header 태그 가져오기 (존재하면 출력)
    header_tag = self.soup.select("header")
    # html이니까 br 태그로 줄 바꿈 해주기
    # select는 return 타입이 array임
    header_text = "<br />".join([tag.get_text(strip=True) for tag in header_tag]) if header_tag else "헤더 정보 없음"

    output += f"<strong>{header_text}</strong><hr/>"

    # 지역별 날씨 정보 추가
    # location 별로 나눠져 있음
    for location in self.soup.select("location"):
      city = location.select_one("city").string
      weather = location.select_one("wf").string
      min_temp = location.select_one("tmn").string
      max_temp = location.select_one("tmx").string

      output += f"<h3>{city}</h3>"
      output += f"<p>날씨: {weather}</p>"
      output += f"<p>최저/최고 기온: {min_temp}/{max_temp}</p>"
      output += "<hr />"

    # HTML 마무으리
    output += """
    </body>
    </html>
    """

    return output

# Flask 웹 서버 생성
app = Flask(__name__)

# 루트 경로로 실행
@app.route("/")
def hello():
  """Flask 라우트에서 WeatherScraper(클래스)를 활용하여 HTML 반환"""
  scraper = WeatherScraper("http://www.kma.go.kr/weather/forecast/mid-term-rss3.jsp?stnId=108")
  scraper.fetch_weather_data()
  scraper.save_to_file()  # result.html 파일 저장
  return scraper.parse_weather()  # HTML 문서 전체 반환

 

기본 숙제 코드 beautiful_flask.py 와 다른 점

  • WeatherScraper 클래스를 사용하여 데이터를 가져오고 파싱하는 기능을 모듈화했습니다.
  • 지역, 날씨, 최저/최고 기온 데이터 외에 HTML <head> 태그 RSS에 있는 <header> 데이터를 포함했습니다.
  • print()를 사용해서 데이터를 확인하려 했지만, 응답 컨텐츠가 너무 길어 파일로 저장하여 디버깅했습니다.

 

export FLASK_APP=<파일명>.py # ./beautiful_soup
flask run
http://127.0.0.1:5000

결과

728x90