Chuyển tới nội dung chính

🐍 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​

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:

Mở trên Colab

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ểmDùng khi
REST APIGọi → nhận → kết thúcLấy dữ liệu định kỳ, thao tác CRUD
WebSocketKết nối mở liên tục, server đẩy dữ liệuDữ liệu realtime, giá, order book
WebhookServer chủ động gọi vào app của bạnNhậ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ố request1 request/giây1 kết nối duy nhất
Bị rate limitCó thểRất khó
Độ trễ100–500ms10–100ms
Mất dữ liệuCó — bỏ qua biến động giữa hai lần gọiKhông
Dễ triển khaiRất dễCần xử lý kết nối lại
Phù hợpKiể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:

  1. Ghi theo lô, không ghi từng bản ghi — mở/đóng file liên tục rất chậm.
  2. Ghim rõ thời gian — luôn lưu timestamp, đừng dựa vào thứ tự file.
  3. Xoay file theo ngày — gia-2026-10-02.csv tố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ỗiHậu quảCách sửa
Không có timeoutScript treo vô hạn khi mạng lỗiLuôn đặt timeout=10
Vòng lặp gọi API không sleepBị chặn IP (429/418)time.sleep() giữa các lần gọi
Không xử lý JSON lỗiCrash khi server trả HTMLBọ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