Python #02 · 파일 저장 + FastAPI + MySQL
날씨 데이터 저장하고
API 서버 + DB까지 만들기
오늘 한 것
#01에서 날씨 API를 호출해 터미널에 출력하는 것까지 만들었다. 이번엔 네 가지를 더 붙였다.
01
날씨 API 호출 (지난 포스팅)
requests.get() 으로 wttr.in API 호출, 딕셔너리로 가공
02
JSON 파일로 저장
결과를 result.json 파일로 저장
03
FastAPI 서버 만들기
브라우저에서 /weather/Seoul 로 조회
04
여러 도시 HTML 리포트 자동 생성
Python이 HTML 파일을 자동으로 만들어서 브라우저에서 확인
05
MySQL에 날씨 기록 저장
pymysql로 DB 연결, weather_log 테이블에 INSERT
JSON 파일로 저장하기
터미널 출력만으로는 결과가 사라진다. 파일로 저장해두면 나중에 읽거나 다른 곳에서 활용할 수 있다.
import json # 맨 위에 추가
with open("result.json", "w", encoding="utf-8") as f:
json.dump(w, f, ensure_ascii=False, indent=2)
print("result.json 저장 완료!")
open()
파일을 열거나 새로 만든다.
"w"는 쓰기 모드.open("파일명", "w", encoding="utf-8")
with 문
블록이 끝나면 파일을 자동으로 닫아준다. Java의 try-with-resources와 같다.
with open(...) as f: ...
json.dump()
딕셔너리를 JSON 형식으로 파일에 저장한다.
json.dump(w, f, indent=2)
ensure_ascii=False
한글이 깨지지 않게 한다.
ensure_ascii=False
indent=2
들여쓰기를 적용해서 사람이 읽기 좋게 만든다.
indent=2 → 공백 2칸
FastAPI로 API 서버 만들기
터미널에서만 쓰던 걸 브라우저에서 URL로 조회할 수 있게 만들었다. Java의 @GetMapping과 같은 개념이다.
pip install fastapi uvicorn
from fastapi import FastAPI
from weather import get_weather, get_emoji
app = FastAPI()
@app.get("/weather/{city}")
def weather(city: str):
w = get_weather(city)
w["emoji"] = get_emoji(w["desc"])
return w
uvicorn main:app --reload
GEThttp://127.0.0.1:8000/weather/Seoul
{ "city" : "Seoul", "temp_c": 18, "desc" : "맑음", "emoji" : "☀️" }
FastAPI()
앱 인스턴스 생성. Java의 Spring 컨테이너와 비슷한 역할.
app = FastAPI()
@app.get()
GET 요청을 처리하는 엔드포인트 등록. Java의 @GetMapping과 같다.
@app.get("/weather/{city}")
{city} 경로 변수
URL의 일부를 변수로 받는다. Java의 @PathVariable과 같다.
/weather/Seoul → city = "Seoul"
uvicorn
FastAPI를 실행하는 서버. Java의 내장 Tomcat과 같은 역할.
uvicorn main:app --reload
--reload
코드 수정 시 서버 자동 재시작. Spring DevTools와 같다.
파일 저장만 해도 반영됨
/docs
FastAPI가 자동으로 만들어주는 Swagger 문서.
http://127.0.0.1:8000/docs
여러 도시 HTML 리포트 자동 생성
여러 도시 날씨를 한 번에 가져와서 HTML 파일로 자동 생성했다. Python이 HTML을 직접 문자열로 만들어서 파일로 저장하는 방식이다.
import json
from weather import get_weather, get_emoji
cities = ["Seoul", "Incheon", "Busan", "Jeju"]
results = []
for city in cities:
w = get_weather(city)
w["emoji"] = get_emoji(w["desc"])
results.append(w)
print(f"{w['emoji']} {w['city']} {w['temp_c']}°C 완료")
# HTML 파일 자동 생성
html = """<!DOCTYPE html>...""" # 카드 HTML 생성
with open("weather_report.html", "w", encoding="utf-8") as f:
f.write(html)
print("weather_report.html 생성 완료!")
실행 결과로 생성된 HTML을 브라우저로 열면 이렇게 카드 형태로 볼 수 있다.
☀️ Seoul 18°C 완료 ☀️ Munhaktong 12°C 완료 🌧️ Yangchong 2Dong 14°C 완료 🌤️ Minjondong 12°C 완료 weather_report.html 생성 완료!
list.append()
리스트에 항목을 추가한다. Java의 list.add()와 같다.
results.append(w)
f.write()
파일에 문자열을 쓴다. HTML을 문자열로 만들어서 파일로 저장.
f.write(html)
f-string in loop
반복문 안에서 f-string으로 HTML 카드를 동적으로 생성한다.
html += f"<div>{w['city']}</div>"
MySQL에 날씨 기록 저장하기
날씨 데이터를 MySQL DB에 저장했다. Python에서 MySQL을 연결할 때는 pymysql 라이브러리를 사용한다. Java의 JDBC와 같은 역할이다.
pip install pymysql
CREATE DATABASE weather_db;
USE weather_db;
CREATE TABLE weather_log (
id INT AUTO_INCREMENT PRIMARY KEY,
city VARCHAR(100),
country VARCHAR(100),
temp_c INT,
feels_like INT,
humidity INT,
desc_text VARCHAR(100),
wind_kmph INT,
updated_at VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
import pymysql
import json
conn = pymysql.connect(
host="localhost",
user="root",
password="****",
database="weather_db",
charset="utf8mb4"
)
cursor = conn.cursor()
with open("cities.json", "r", encoding="utf-8") as f:
cities = json.load(f)
for w in cities:
sql = """
INSERT INTO weather_log
(city, country, temp_c, feels_like, humidity, desc_text, wind_kmph, updated_at)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
"""
cursor.execute(sql, (
w["city"], w["country"], w["temp_c"], w["feels_like"],
w["humidity"], w["desc"], w["wind_kmph"], w["updated_at"]
))
print(f"저장 완료: {w['city']}")
conn.commit()
cursor.close()
conn.close()
DB에 저장된 결과를 MySQL에서 조회하면 이렇게 나온다.
| id | city | temp_c | desc_text | humidity | created_at |
|---|---|---|---|---|---|
| 1 | Seoul | 18 | 맑음 | 45 | 2026-03-25 13:37 |
| 2 | Munhaktong | 12 | 맑음 | 67 | 2026-03-25 13:37 |
| 3 | Yangchong 2Dong | 14 | 가벼운 비 | 51 | 2026-03-25 13:37 |
| 4 | Minjondong | 12 | 흐린 | 82 | 2026-03-25 13:37 |
pymysql.connect()
MySQL에 연결한다. Java의 DriverManager.getConnection()과 같다.
conn = pymysql.connect(host, user, password, database)
conn.cursor()
SQL을 실행할 커서를 가져온다. Java의 Statement와 같다.
cursor = conn.cursor()
cursor.execute()
SQL을 실행한다. %s로 파라미터를 바인딩해서 SQL Injection을 방지한다.
cursor.execute(sql, (값1, 값2, ...))
conn.commit()
변경사항을 DB에 반영한다. 이걸 빠뜨리면 저장이 안 된다.
conn.commit()
json.load()
JSON 파일을 읽어서 딕셔너리로 변환한다. dump()의 반대.
json.load(f) ↔ json.dump(w, f)
cursor.close() / conn.close()
커서와 연결을 닫는다. Java의 finally 블록에서 close() 하는 것과 같다.
cursor.close() → conn.close()
이번에 익힌 것들
with open()으로 파일 열고 자동으로 닫는 패턴json.dump()저장,json.load()읽기- FastAPI로 GET 엔드포인트 만드는 방법 —
@app.get() - URL 경로 변수
{city}받는 방법 — Java의 @PathVariable - Python이 HTML을 문자열로 만들어서 파일로 저장하는 패턴
pymysql.connect()로 MySQL 연결cursor.execute(sql, (값...))로 INSERT 실행conn.commit()빠뜨리면 저장 안 된다는 것
다음에 만들 것
'Python' 카테고리의 다른 글
| React + FastAPI로 웹 게임 만들기 #4 - Render + Vercel 배포 (0) | 2026.04.24 |
|---|---|
| React + FastAPI로 웹 게임 만들기 #3 - 완성 (0) | 2026.04.23 |
| React + Python FastAPI로웹 게임 만들기 #2 (0) | 2026.04.23 |
| React + Python FastAPI로웹 게임 만들기 #1 (1) | 2026.04.22 |
| 🌤️날씨 데이터(1) - 날씨 정보 가져오기 (외부 API 호출) (0) | 2026.03.25 |