13장: 웹 API 맛보기 - 데이터 받아오기¶
🎯 이 장에서 배우는 것¶
- [ ] HTTP 요청의 기본 개념을 설명할 수 있다
- [ ] urequests로 API를 호출할 수 있다
- [ ] JSON 데이터를 파싱하여 활용할 수 있다
💡 왜 이걸 배우나요?¶
스마트폰 날씨 앱은 어떻게 전 세계 날씨를 알까요? 직접 측정할까요? 아닙니다! 인터넷에서 데이터를 받아오는 거예요.
인터넷에는 날씨, 뉴스, 주가, 환율 등 수많은 데이터가 API(Application Programming Interface)라는 형태로 제공됩니다. API는 마치 데이터 자판기와 같아요. 요청을 보내면 원하는 데이터를 돌려줍니다.
우리 피코도 WiFi에 연결했으니, 이제 전 세계의 데이터를 받아올 수 있어요! 오늘은 실제로 OpenWeatherMap에서 현재 날씨를 받아와 볼 거예요. 🌤️
📚 핵심 개념¶
개념 1: HTTP 요청과 응답¶
-
비유로 시작: "HTTP는 마치 식당 주문 시스템과 같아요. 손님(피코)이 주문서(요청)를 보내면, 주방(서버)이 음식(데이터)을 내어줍니다."
-
정확한 정의: HTTP(HyperText Transfer Protocol)는 웹에서 데이터를 주고받는 규칙입니다. 클라이언트가 요청(Request)을 보내면, 서버가 응답(Response)을 돌려줍니다.
-
예시로 확인:
피코: "서울 날씨 주세요!" (요청) 서버: "현재 15도, 맑음입니다" (응답)
쉽게 말하면: 질문하면 답을 주는 대화 방식이에요!
개념 2: API와 API 키¶
-
비유로 시작: "API는 데이터 자판기예요. 동전(API 키)을 넣고 버튼(요청)을 누르면 음료(데이터)가 나와요."
-
정확한 정의: API는 프로그램끼리 데이터를 주고받는 약속된 방법입니다. API 키는 "누가 요청했는지" 확인하는 신분증이에요.
-
예시로 확인: OpenWeatherMap은 무료로 날씨 데이터를 제공하지만, API 키가 있어야 사용할 수 있어요.
쉽게 말하면: API는 데이터 창구, API 키는 입장권!
개념 3: JSON 데이터 형식¶
-
비유로 시작: "JSON은 정리된 서랍장과 같아요. 각 서랍에 이름표가 붙어있고, 그 안에 물건(데이터)이 들어있죠."
-
정확한 정의: JSON(JavaScript Object Notation)은 데이터를
{"키": "값"}형태로 저장하는 형식입니다. 사람도 읽기 쉽고, 컴퓨터도 처리하기 쉬워요. -
예시로 확인:
{ "city": "Seoul", "temp": 15, "weather": "맑음" }
쉽게 말하면: 이름표가 붙은 데이터 묶음이에요!
🔨 따라하기¶
Step 1: HTTP 요청 보내기¶
목표: urequests 라이브러리로 웹 페이지 받아오기
먼저 간단한 테스트 사이트에 요청을 보내봅시다.
코드 (step1_http_request.py):
# === WHAT: 웹 서버에 HTTP 요청 보내기 ===
# 인터넷의 데이터를 받아오는 첫 걸음!
# --- WHY: 왜 필요한지 ---
# API를 사용하려면 먼저 HTTP 요청을 보낼 줄 알아야 해요
import network # WiFi 연결용
import urequests # HTTP 요청용
import time
# HOW: 어떻게 동작하는지
# 1. WiFi 연결 (11차시에서 배운 내용)
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("your_wifi_name", "your_wifi_password") # 🔧 수정하세요!
print("WiFi 연결 중...")
while not wlan.isconnected():
time.sleep(1)
print("WiFi 연결 완료!")
print(f"IP: {wlan.ifconfig()[0]}")
# 2. HTTP GET 요청 보내기
url = "http://httpbin.org/ip" # 테스트용 사이트
print(f"\n{url} 에 요청 중...")
response = urequests.get(url) # GET 요청!
# 3. 응답 확인
print(f"상태 코드: {response.status_code}") # 200이면 성공
print(f"응답 내용: {response.text}")
response.close() # 연결 닫기 (중요!)
실행 결과:
WiFi 연결 완료!
IP: 192.168.0.15
http://httpbin.org/ip 에 요청 중...
상태 코드: 200
응답 내용: {
"origin": "123.45.67.89"
}
여기서 잠깐! 🤔
- 상태 코드 200은 "성공"이라는 뜻이에요
- response.close()를 꼭 호출해야 메모리 누수를 막아요!
Step 2: 날씨 API 호출하기¶
목표: OpenWeatherMap API로 실제 날씨 데이터 받아오기
📌 사전 준비: openweathermap.org에서 무료 계정을 만들고 API 키를 받으세요! (가입 후 이메일 인증 필요)
코드 (step2_weather_api.py):
# === WHAT: OpenWeatherMap 날씨 API 호출 ===
# 실제 서울의 현재 날씨를 받아옵니다!
import network
import urequests
import time
# WiFi 연결 (간략화)
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("your_wifi_name", "your_wifi_password") # 🔧 수정!
while not wlan.isconnected():
time.sleep(1)
print("WiFi 연결 완료!")
# --- 날씨 API 설정 ---
API_KEY = "your_api_key_here" # 🔧 여기에 API 키 입력!
CITY = "Seoul"
# API URL 만들기
url = f"http://api.openweathermap.org/data/2.5/weather?q={CITY}&appid={API_KEY}&units=metric"
# units=metric: 섭씨 온도로 받기
print(f"\n{CITY} 날씨 요청 중...")
response = urequests.get(url)
if response.status_code == 200:
print("✅ 성공!")
print(response.text[:200]) # 처음 200자만 출력
else:
print(f"❌ 오류: {response.status_code}")
response.close()
실행 결과:
WiFi 연결 완료!
Seoul 날씨 요청 중...
✅ 성공!
{"coord":{"lon":126.9778,"lat":37.5683},"weather":[{"id":800,"main":"Clear","description":"clear sky"}],"main":{"temp":15.2,"feels_like":14.1}...
여기서 잠깐! 🤔 받아온 데이터가 복잡해 보이죠? 이게 바로 JSON이에요! 다음 단계에서 필요한 정보만 뽑아볼게요.
Step 3: JSON 파싱하여 날씨 표시하기¶
목표: JSON에서 온도와 날씨 정보 추출하기
코드 (step3_json_parse.py):
# === WHAT: JSON 데이터 파싱하기 ===
# 복잡한 JSON에서 원하는 정보만 쏙쏙 뽑아요!
import network
import urequests
import time
# WiFi 연결
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("your_wifi_name", "your_wifi_password") # 🔧 수정!
while not wlan.isconnected():
time.sleep(1)
print("WiFi 연결 완료!\n")
# 날씨 API 호출
API_KEY = "your_api_key_here" # 🔧 수정!
CITY = "Seoul"
url = f"http://api.openweathermap.org/data/2.5/weather?q={CITY}&appid={API_KEY}&units=metric"
response = urequests.get(url)
if response.status_code == 200:
# --- JSON 파싱하기 ---
data = response.json() # 문자열 → 딕셔너리 변환!
# 원하는 정보 추출
temp = data["main"]["temp"] # 현재 온도
feels_like = data["main"]["feels_like"] # 체감 온도
humidity = data["main"]["humidity"] # 습도
weather = data["weather"][0]["main"] # 날씨 상태
description = data["weather"][0]["description"] # 상세 설명
# 예쁘게 출력
print("=" * 30)
print(f"🌍 {CITY} 현재 날씨")
print("=" * 30)
print(f"🌡️ 온도: {temp}°C")
print(f"🤔 체감: {feels_like}°C")
print(f"💧 습도: {humidity}%")
print(f"☁️ 날씨: {weather}")
print(f"📝 설명: {description}")
print("=" * 30)
else:
print(f"오류 발생: {response.status_code}")
response.close()
실행 결과:
WiFi 연결 완료!
==============================
🌍 Seoul 현재 날씨
==============================
🌡️ 온도: 15.2°C
🤔 체감: 14.1°C
💧 습도: 62%
☁️ 날씨: Clear
📝 설명: clear sky
==============================
여기서 잠깐! 🤔
- response.json()이 마법처럼 JSON을 파이썬 딕셔너리로 바꿔줘요
- data["main"]["temp"]는 "main 서랍 안의 temp 값"을 의미해요
📝 전체 코드¶
# === 서울 날씨 알리미 완성판 ===
# WiFi 연결 → API 호출 → JSON 파싱 → 출력
import network
import urequests
import time
# ====== 설정 (여기만 수정하세요!) ======
WIFI_SSID = "your_wifi_name" # 🔧 WiFi 이름
WIFI_PASSWORD = "your_password" # 🔧 WiFi 비밀번호
API_KEY = "your_api_key" # 🔧 OpenWeatherMap API 키
CITY = "Seoul" # 도시 이름 (영어)
# ======================================
def connect_wifi():
"""WiFi에 연결합니다"""
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
print("WiFi 연결 중", end="")
timeout = 10
while not wlan.isconnected() and timeout > 0:
print(".", end="")
time.sleep(1)
timeout -= 1
if wlan.isconnected():
print("\n✅ WiFi 연결 성공!")
return True
else:
print("\n❌ WiFi 연결 실패")
return False
def get_weather():
"""날씨 정보를 가져옵니다"""
url = f"http://api.openweathermap.org/data/2.5/weather?q={CITY}&appid={API_KEY}&units=metric"
try:
response = urequests.get(url)
if response.status_code == 200:
data = response.json()
weather_info = {
"temp": data["main"]["temp"],
"feels_like": data["main"]["feels_like"],
"humidity": data["main"]["humidity"],
"weather": data["weather"][0]["main"],
"description": data["weather"][0]["description"]
}
response.close()
return weather_info
else:
response.close()
return None
except Exception as e:
print(f"오류: {e}")
return None
def display_weather(info):
"""날씨 정보를 예쁘게 출력합니다"""
print("\n" + "=" * 30)
print(f"🌍 {CITY} 현재 날씨")
print("=" * 30)
print(f"🌡️ 온도: {info['temp']}°C")
print(f"🤔 체감: {info['feels_like']}°C")
print(f"💧 습도: {info['humidity']}%")
print(f"☁️ 날씨: {info['weather']}")
print(f"📝 설명: {info['description']}")
print("=" * 30)
# 메인 실행
if connect_wifi():
weather = get_weather()
if weather:
display_weather(weather)
else:
print("날씨 정보를 가져오지 못했습니다.")
⚠️ 자주 하는 실수¶
실수 1: API 키를 그대로 사용¶
증상: {"cod": 401, "message": "Invalid API key"}
원인: API 키를 발급받지 않았거나, 복사할 때 공백이 포함됨
해결:
# 잘못된 코드
API_KEY = "your_api_key_here" # 예시 그대로 사용
# 올바른 코드
API_KEY = "a1b2c3d4e5f6..." # 본인의 실제 API 키!
실수 2: response.close() 누락¶
증상: 여러 번 실행하면 OSError: [Errno 12] ENOMEM (메모리 부족)
원인: 연결을 닫지 않아 메모리 누수 발생
해결:
# 잘못된 코드
response = urequests.get(url)
data = response.json()
# close() 없이 끝남
# 올바른 코드
response = urequests.get(url)
data = response.json()
response.close() # 반드시 닫기!
실수 3: JSON 키 이름 오타¶
증상: KeyError: 'temprature'
원인: JSON 키 이름을 잘못 입력 (temp를 temprature로)
해결:
# 잘못된 코드
temp = data["main"]["temprature"] # 오타!
# 올바른 코드
temp = data["main"]["temp"] # 정확한 키 이름
# 💡 팁: 먼저 전체 데이터를 출력해서 키 이름 확인!
print(data)
✅ 스스로 점검하기¶
-
HTTP GET 요청에서 "GET"의 의미는 무엇인가요?
-
다음 JSON에서 도시 이름을 추출하는 코드는?
{"location": {"city": "Seoul", "country": "KR"}} -
response.close()를 꼭 호출해야 하는 이유는?
정답 확인
1. **GET**은 "데이터를 가져오다"라는 의미예요. 서버에서 정보를 **읽어오는** 요청입니다. (POST는 데이터를 **보내는** 요청) 2. ```python data = response.json() city = data["location"]["city"] # "Seoul" ``` 3. 피코는 메모리가 제한적이에요. `close()`를 호출하지 않으면 연결이 계속 열려있어 **메모리 누수**가 발생하고, 결국 프로그램이 멈춥니다!🚀 더 해보기¶
도전 1: 다른 도시 날씨 받아오기¶
CITY = "Seoul"을 다른 도시로 바꿔보세요!
- Tokyo, London, New York, Paris 등
도전 2: 날씨에 따른 이모지 표시¶
날씨 상태에 맞는 이모지를 출력하세요:
weather = data["weather"][0]["main"]
if weather == "Clear":
emoji = "☀️"
elif weather == "Clouds":
emoji = "☁️"
elif weather == "Rain":
emoji = "🌧️"
# ... 더 추가해보세요!
도전 3: OLED에 날씨 표시하기 ⭐¶
10차시에서 배운 OLED를 활용해서 날씨를 화면에 표시해보세요!
힌트:
oled.fill(0)
oled.text(f"Seoul", 0, 0)
oled.text(f"Temp: {temp}C", 0, 16)
oled.text(f"Weather: {weather}", 0, 32)
oled.show()
🔗 다음 장으로¶
오늘 배운 것: - ✅ HTTP 요청으로 인터넷 데이터 받아오기 - ✅ API 키로 날씨 서비스 사용하기 - ✅ JSON 파싱으로 원하는 정보 추출하기
🎉 이제 우리 피코가 인터넷의 정보를 활용할 수 있게 됐어요!
다음 장에서는 12차시의 시계와 오늘의 날씨 API를 합쳐서 IoT 날씨 시계를 완성합니다. 시간과 날씨가 함께 표시되는 스마트 기기를 만들어봐요! ⏰🌤️