🐍 Ngày 41 - Python hằng ngày 365 ngày - Tương tác với dữ liệu từ API, giao tiếp với thế giới
🔹 API là gì?
API (Application Programming Interface) là cầu nối giúp các ứng dụng/phần mềm giao tiếp với nhau.
Bạn có thể hình dung nó giống như một thực đơn ở nhà hàng:
- Bạn gọi món → (Gửi yêu cầu - Request)
- Bếp nấu và trả món lại → (Phản hồi - Response)
🔹 Mục tiêu học hôm nay
- Hiểu API là gì
- Biết cách gọi một REST API bằng Python
- Làm việc với dữ liệu JSON
- Biết gửi các loại request: GET và POST
🔹 Công cụ cần dùng
- Thư viện
requests
Cài đặt nếu chưa có:
pip install requests
🔹 Ví dụ 1: Gọi API đơn giản
import requests
response = requests.get("https://api.agify.io/?name=thanh")
data = response.json()
print(data)
# Output ví dụ: {'name': 'thanh', 'age': 26, 'count': 1234}
🔹 Ví dụ 2: Gửi dữ liệu bằng POST
import requests
url = "https://httpbin.org/post"
payload = {"name": "thanh", "job": "dev"}
response = requests.post(url, json=payload)
print(response.json())
🔹 Bài tập gợi ý
Làm một trong các mini-project sau để luyện tập:
- ✅ Gọi API dự đoán tuổi từ tên (Agify)
- ✅ Gọi API dự báo thời tiết (OpenWeatherMap)
- ✅ Tạo app nhỏ nhập tên → gọi API → hiển thị tuổi và giới tính
🎯 Kết luận
API là một phần cực kỳ quan trọng trong lập trình hiện đại. Làm chủ API giúp bạn:
- Tương tác với web services
- Giao tiếp giữa các hệ thống
- Xây dựng các ứng dụng thông minh, kết nối tốt hơn
💬 Bạn đã sẵn sàng kết nối với thế giới qua API chưa?
Bạn có thể mở bài học này trên Google Colab để chạy trực tiếp:
Hướng dẫn API với Python
Dưới đây là video hướng dẫn cách làm việc với API trong Python:
🌍 Ba cách "giao tiếp với thế giới" từ Python
| Cách | Đặc điểm | Dùng khi |
|---|---|---|
| REST API | Gọi → nhận → kết thúc | Lấy dữ liệu định kỳ, thao tác CRUD |
| WebSocket | Kết nối mở liên tục, server đẩy dữ liệu | Dữ liệu realtime, giá, order book |
| Webhook | Server chủ động gọi vào app của bạn | Nhận thông báo sự kiện (thanh toán, alert) |
REST API (kéo dữ liệu về):
Python ──request──> Server
<──response──
(kết thúc)
WebSocket (dòng dữ liệu liên tục):
Python ══kết nối══> Server
<═══ giá liên tục ═══
(giữ mở)
Webhook (server đẩy vào bạn):
Server ──POST──> App của bạn
🔴 WebSocket — nhận dữ liệu realtime
# pip install websocket-client
import json
import websocket
from datetime import datetime
def theo_doi_gia(symbol: str = "btcusdt", so_cap_nhat: int = 20) -> None:
"""Theo dõi giá realtime qua WebSocket Binance."""
url = f"wss://stream.binance.com:9443/ws/{symbol}@trade"
dem = 0
def khi_mo(ws):
print(f"✅ Đã kết nối: {symbol.upper()}")
def khi_nhan(ws, thong_diep):
nonlocal dem
du_lieu = json.loads(thong_diep)
dem += 1
gia = float(du_lieu["p"])
khoi_luong = float(du_lieu["q"])
thoi_gian = datetime.fromtimestamp(du_lieu["T"] / 1000)
print(f"[{dem:>3}] {thoi_gian:%H:%M:%S} "
f"{gia:>12,.2f} KL {khoi_luong:>8.4f}")
if dem >= so_cap_nhat:
ws.close()
websocket.WebSocketApp(
url, on_open=khi_mo, on_message=khi_nhan
).run_forever()
# theo_doi_gia()
⚠️ Luôn có cơ chế dừng. WebSocket chạy vô hạn. Nếu không có điều kiện dừng, script của bạn sẽ chạy mãi. Trong bot thật, hãy thêm: giới hạn thời gian, giới hạn số bản ghi, và xử lý mất kết nối.
🔁 So sánh polling vs WebSocket
import time
import urllib.request
import json
def poll_gia(symbol: str = "BTCUSDT", so_lan: int = 10, giay: int = 1):
"""Cách polling — chủ động hỏi liên tục."""
for i in range(so_lan):
url = f"https://api.binance.com/api/v3/ticker/price?symbol={symbol}"
with urllib.request.urlopen(url, timeout=10) as r:
gia = float(json.loads(r.read().decode())["price"])
print(f"[{i+1:>3}] {gia:,.2f}")
time.sleep(giay)
| Tiêu chí | Polling (REST) | WebSocket |
|---|---|---|
| Số request | 1 request/giây | 1 kết nối duy nhất |
| Bị rate limit | Có thể | Rất khó |
| Độ trễ | 100–500ms | 10–100ms |
| Mất dữ liệu | Có — bỏ qua biến động giữa hai lần gọi | Không |
| Dễ triển khai | Rất dễ | Cần xử lý kết nối lại |
| Phù hợp | Kiểm tra định kỳ | Bot, giám sát realtime |
Quy tắc chọn: nếu cần dữ liệu mỗi giây trở lên, dùng WebSocket. Nếu chỉ cần mỗi phút, polling đơn giản hơn và đủ tốt.
📁 Ghi dữ liệu realtime ra file
import csv
from pathlib import Path
def ghi_gia_realtime(du_lieu_list: list[tuple], ten_file: str = "gia-realtime.csv"):
"""Ghi danh sách (thoi_gian, gia, khoi_luong) vào CSV."""
file = Path(ten_file)
moi_file = not file.exists()
with open(file, "a", newline="", encoding="utf-8-sig") as f:
writer = csv.writer(f)
if moi_file:
writer.writerow(["thoi_gian", "gia", "khoi_luong"])
writer.writerows(du_lieu_list)
💡 Ba quy tắc lưu dữ liệu realtime:
- Ghi theo lô, không ghi từng bản ghi — mở/đóng file liên tục rất chậm.
- Ghim rõ thời gian — luôn lưu timestamp, đừng dựa vào thứ tự file.
- Xoay file theo ngày —
gia-2026-10-02.csvtốt hơn một file khổng lồ.
📊 Bảng giá tự làm mới trong terminal
import os
import time
import urllib.request
import json
CAP = ["BTCUSDT", "ETHUSDT", "SOLUSDT", "BNBUSDT"]
def lay_gia(cap: str):
try:
url = f"https://api.binance.com/api/v3/ticker/24hr?symbol={cap}"
with urllib.request.urlopen(url, timeout=10) as r:
d = json.loads(r.read().decode())
return float(d["lastPrice"]), float(d["priceChangePercent"])
except Exception:
return None
def hien_thi():
while True:
os.system("cls" if os.name == "nt" else "clear")
print(f"📈 BẢNG GIÁ — {time.strftime('%H:%M:%S')}\n")
print(f"{'CẶP':<12} {'GIÁ':>14} {'24H':>10}")
print("-" * 38)
for cap in CAP:
kq = lay_gia(cap)
if kq:
gia, thay_doi = kq
mui = "🟢" if thay_doi >= 0 else "🔴"
print(f"{cap:<12} {gia:>14,.2f} {mui}{thay_doi:>+8.2f}%")
else:
print(f"{cap:<12} {'LỖI':>14}")
print("\nCtrl+C để dừng")
time.sleep(5)
🧯 Bốn lỗi thường gặp khi làm việc với API
| Lỗi | Hậu quả | Cách sửa |
|---|---|---|
Không có timeout | Script treo vô hạn khi mạng lỗi | Luôn đặt timeout=10 |
Vòng lặp gọi API không sleep | Bị chặn IP (429/418) | time.sleep() giữa các lần gọi |
| Không xử lý JSON lỗi | Crash khi server trả HTML | Bọc json.loads trong try/except |
| In dữ liệu thô | Không đọc được gì | Định dạng số bằng f-string |
📝 Bài tập mở rộng
Bài 1: Đồng hồ giá
Xây bảng giá tự làm mới mỗi 5 giây cho 5 cặp.
Bài 2: WebSocket đơn giản
Kết nối WebSocket Binance, in ra 50 giao dịch đầu tiên của BTCUSDT.
Bài 3: Ghi log realtime
Thu thập giá mỗi giây trong 1 phút qua WebSocket, lưu vào CSV.
Bài 4: Xử lý mất kết nối
Thêm vào code WebSocket khả năng tự kết nối lại khi mất mạng (dùng on_error và on_close).
🎯 Tóm tắt ngày 41
✅ Phân biệt REST API, WebSocket, webhook ✅ Dùng WebSocket nhận dữ liệu realtime ✅ Biết khi nào polling đủ tốt, khi nào cần WebSocket ✅ Ghi dữ liệu realtime ra file đúng cách ✅ Tạo bảng theo dõi giá ngay trong terminal