Nhập môn API và Tại sao Python requests lại quan trọng?
Trong công việc IT, việc các ứng dụng ‘nói chuyện’ với nhau diễn ra hàng ngày. Có thể bạn cần lấy dữ liệu từ một dịch vụ bên ngoài, gửi thông tin cập nhật lên một nền tảng khác, hoặc tự động hóa tác vụ qua API. Python requests chính là công cụ giúp bạn làm điều đó một cách hiệu quả.
Ban đầu, nhiều lập trình viên có thể nghĩ đến urllib – thư viện có sẵn của Python. Tuy nhiên, họ nhanh chóng nhận ra urllib khá phức tạp và cồng kềnh cho các tác vụ HTTP thông thường.
Vấn đề nằm ở chỗ, urllib đòi hỏi bạn phải tự tay xử lý nhiều chi tiết cấp thấp của HTTP. Chẳng hạn như việc mã hóa tham số, quản lý header hay giải mã phản hồi. Điều này làm cho code dài dòng, khó đọc, đặc biệt với những người mới bắt đầu. Đó là lúc thư viện requests trở thành giải pháp tối ưu.
requests ra đời để đơn giản hóa việc gửi yêu cầu HTTP trong Python. Nó khéo léo ẩn đi những phức tạp của giao tiếp web, giúp bạn tập trung vào logic ứng dụng thay vì các chi tiết giao thức HTTP. Trên thực tế, requests đã trở thành lựa chọn hàng đầu của phần lớn lập trình viên Python khi cần tương tác với API, nhờ sự tiện lợi và mạnh mẽ của nó.
Quick Start: Gọi API trong 5 phút
Để bạn dễ hình dung, chúng ta hãy bắt đầu ngay với requests. Bạn hãy mở terminal và cùng thực hành nhé.
Bước 1: Cài đặt thư viện requests
Đảm bảo bạn đã cài đặt Python. Sau đó, dùng pip để cài requests:
pip install requests
Bước 2: Gửi yêu cầu GET đơn giản
Yêu cầu GET dùng để lấy dữ liệu từ server. Giả sử mình muốn lấy danh sách bài viết từ một API công cộng (ví dụ: JSONPlaceholder).
import requests
# Gửi yêu cầu GET đến một API công cộng
response = requests.get('https://jsonplaceholder.typicode.com/posts/1')
# Kiểm tra mã trạng thái HTTP
if response.status_code == 200:
# In nội dung phản hồi dưới dạng JSON
print("GET thành công!")
print(response.json())
else:
print(f"Có lỗi xảy ra: {response.status_code}")
Thật đơn giản phải không? Chỉ với vài dòng code, bạn đã lấy được dữ liệu từ API thành công.
Bước 3: Gửi yêu cầu POST để tạo dữ liệu
Yêu cầu POST thường dùng để gửi dữ liệu lên server, ví dụ tạo một bài viết mới.
import requests
url = 'https://jsonplaceholder.typicode.com/posts'
new_post = {
"title": "Bài viết mới của mình",
"body": "Nội dung thú vị về requests API.",
"userId": 1
}
# Gửi yêu cầu POST với dữ liệu JSON
response = requests.post(url, json=new_post)
# Kiểm tra và in kết quả
if response.status_code == 201: # 201 Created
print("POST thành công!")
print(response.json())
else:
print(f"Có lỗi xảy ra: {response.status_code}")
Ở ví dụ này, đối số json=new_post giúp requests tự động mã hóa dictionary new_post thành JSON và thiết lập header Content-Type: application/json cho bạn. Cực kỳ tiện lợi!
Giải thích chi tiết: Tối ưu hóa giao tiếp API
Các phương thức HTTP cơ bản
HTTP có nhiều phương thức (verb) để chỉ định loại hành động bạn muốn thực hiện trên tài nguyên:
GET: Lấy dữ liệu.POST: Gửi dữ liệu mới để tạo tài nguyên.PUT: Cập nhật toàn bộ tài nguyên hiện có.PATCH: Cập nhật một phần tài nguyên hiện có.DELETE: Xóa tài nguyên.
requests cung cấp các hàm tương ứng: requests.get(), requests.post(), requests.put(), requests.patch(), requests.delete().
Tham số (Parameters) và Header
Khi gửi yêu cầu GET, bạn thường cần truyền các tham số vào URL. requests xử lý việc này gọn gàng bằng cách dùng đối số params.
import requests
# Ví dụ lấy bài viết của userId = 1
params = {'userId': 1}
response = requests.get('https://jsonplaceholder.typicode.com/posts', params=params)
print("Các bài viết của User ID 1:")
for post in response.json():
print(f"- {post['title']}")
Header (tiêu đề) chứa siêu dữ liệu quan trọng về yêu cầu hoặc phản hồi, ví dụ như loại nội dung hay token xác thực. Bạn hoàn toàn có thể dễ dàng thêm các header tùy chỉnh:
import requests
headers = {
'User-Agent': 'My Python App v1.0',
'Accept': 'application/json'
}
response = requests.get('https://jsonplaceholder.typicode.com/posts', headers=headers)
print("Header của phản hồi:")
print(response.headers)
Xử lý phản hồi (Response)
Đối tượng response từ requests rất mạnh mẽ. Một số thuộc tính quan trọng:
response.status_code: Mã trạng thái HTTP (200 OK, 404 Not Found, 500 Internal Server Error, v.v.).response.text: Nội dung phản hồi dưới dạng chuỗi (string).response.json(): Chuyển đổi nội dung JSON thành đối tượng Python (dictionary/list). Sẽ báo lỗi nếu nội dung không phải JSON hợp lệ.response.content: Nội dung phản hồi dưới dạng bytes, hữu ích khi làm việc với file nhị phân (ảnh, video).response.headers: Dictionary chứa các header của phản hồi.
Xử lý lỗi và Ngoại lệ
Trong thực tế, không phải lúc nào API cũng trả về kết quả như mong muốn. Chúng ta cần kiểm tra status_code và xử lý các trường hợp lỗi. requests còn cung cấp một phương thức rất hữu ích là response.raise_for_status(). Phương thức này sẽ tự động báo lỗi (raise một HTTPError) nếu status_code là mã lỗi (từ 4xx hoặc 5xx), giúp bạn phát hiện vấn đề nhanh chóng.
import requests
url_invalid = 'https://jsonplaceholder.typicode.com/non-existent-path'
url_valid = 'https://jsonplaceholder.typicode.com/posts/1'
try:
response = requests.get(url_invalid)
response.raise_for_status() # Sẽ raise lỗi cho mã 404
print("GET thành công!")
except requests.exceptions.HTTPError as err:
print(f"Lỗi HTTP: {err}")
except requests.exceptions.ConnectionError as err:
print(f"Lỗi kết nối: {err}")
except requests.exceptions.Timeout as err:
print(f"Lỗi timeout: {err}")
except requests.exceptions.RequestException as err:
print(f"Lỗi chung: {err}")
print("\n--- Thử với URL hợp lệ ---")
try:
response = requests.get(url_valid)
response.raise_for_status()
print("GET hợp lệ thành công!")
print(response.json())
except requests.exceptions.RequestException as err:
print(f"Có lỗi xảy ra: {err}")
Xác thực (Authentication)
Nhiều API yêu cầu xác thực để truy cập. requests hỗ trợ nhiều phương thức:
- Basic Authentication: Dùng username và password.
- Bearer Token (Token dựa trên OAuth2, JWT): Gửi token trong header
Authorization.
import requests
# Basic Auth
# response = requests.get('https://api.example.com/user', auth=('username', 'password'))
# Bearer Token (phổ biến nhất hiện nay)
token = 'your_super_secret_bearer_token'
headers_with_auth = {
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
}
# Giả sử có một API yêu cầu Bearer Token
# response = requests.get('https://api.example.com/data', headers=headers_with_auth)
# print(response.json())
print("Trên đây là các ví dụ minh họa về xác thực Basic Auth và Bearer Token.")
Nâng cao: Hiểu sâu hơn về requests
Sessions: Khi bạn cần duy trì trạng thái
Khi tương tác với một API nhiều lần, việc thiết lập lại kết nối TCP/IP, xử lý cookie và header cho mỗi yêu cầu riêng lẻ sẽ tốn thời gian. requests.Session sinh ra để giải quyết vấn đề này một cách hiệu quả.
Một đối tượng Session sẽ tự động duy trì các cài đặt như header, cookie và thông tin xác thực xuyên suốt các yêu cầu. Điều này đặc biệt hữu ích khi bạn chỉ cần đăng nhập một lần, sau đó thực hiện nhiều tác vụ tiếp theo mà không cần xác thực lại.
import requests
# Tạo một Session
with requests.Session() as session:
# Cấu hình chung cho session (ví dụ: thêm header mặc định)
session.headers.update({
'User-Agent': 'My Custom Python Client',
'Accept-Language': 'en-US,en;q=0.5'
})
# Gửi yêu cầu đầu tiên (ví dụ: đăng nhập, lấy cookie)
# login_data = {'username': 'test', 'password': 'password'}
# login_response = session.post('https://api.example.com/login', json=login_data)
# print(f"Login status: {login_response.status_code}")
# Gửi yêu cầu tiếp theo. Cookie và header đã được duy trì.
# data_response = session.get('https://api.example.com/protected_data')
# print(f"Protected data status: {data_response.status_code}")
# print("Current session cookies:", session.cookies.get_dict())
# Ví dụ với API công cộng để minh họa cơ chế session
print("\n--- Minh họa Session với API công cộng ---")
resp1 = session.get('https://httpbin.org/cookies/set/sessioncookie/12345')
print("Cookies sau request 1:", session.cookies.get_dict())
resp2 = session.get('https://httpbin.org/cookies')
print("Cookies sau request 2 (được duy trì từ request 1):")
print(resp2.json())
Dùng requests.Session() không chỉ tăng hiệu suất mà còn giúp code của bạn gọn gàng hơn. Điều này càng rõ rệt khi bạn gửi nhiều yêu cầu liên tiếp đến cùng một domain.
Timeout: Tránh chờ đợi vô tận
Khi gọi API, server có thể phản hồi chậm hoặc không phản hồi. Nếu không có timeout, ứng dụng của bạn có thể bị treo vô thời hạn. Luôn đặt timeout để kiểm soát thời gian chờ đợi:
import requests
try:
# Chờ tối đa 5 giây để server phản hồi
response = requests.get('https://api.github.com/events', timeout=5)
print("GET thành công với timeout.")
except requests.exceptions.Timeout:
print("Yêu cầu đã hết thời gian (timeout).")
except requests.exceptions.RequestException as e:
print(f"Có lỗi khác xảy ra: {e}")
Proxy: Khi cần ẩn danh hoặc vượt tường lửa
Nếu bạn cần gửi yêu cầu qua proxy, chẳng hạn để vượt tường lửa hay ẩn địa chỉ IP, requests hỗ trợ rất tốt:
import requests
proxies = {
'http': 'http://10.10.1.10:3128',
'https': 'http://10.10.1.10:1080',
}
# response = requests.get('http://example.org', proxies=proxies)
print("Đoạn code trên đã cấu hình proxy cho các yêu cầu.")
print("Lưu ý: Thay đổi địa chỉ proxy bằng địa chỉ thực của bạn nếu cần.")
Tải lên tệp (File Uploads)
Để gửi file lên API, bạn dùng đối số files. requests sẽ tự động xử lý header Content-Type: multipart/form-data.
import requests
# Tạo một file giả để test
with open('test_file.txt', 'w') as f:
f.write('Đây là nội dung của file test.')
url = 'https://httpbin.org/post' # Một API để kiểm tra POST request
with open('test_file.txt', 'rb') as f:
files = {'file': f} # 'file' là tên trường mà API backend mong đợi
response = requests.post(url, files=files)
if response.status_code == 200:
print("Tải file thành công!")
print(response.json()['files'])
else:
print(f"Lỗi khi tải file: {response.status_code}")
Tips thực tế: Kinh nghiệm từ những dự án thật
Sử dụng Session đúng cách
Khi viết script xử lý 100K records, mình học được rằng việc tái sử dụng kết nối (connection pooling) là cực kỳ quan trọng. Cách tiếp cận thông thường là gọi requests.get() hoặc requests.post() cho từng record một.
Tuy nhiên, điều này sẽ tạo và đóng rất nhiều kết nối HTTP, gây lãng phí tài nguyên và làm chậm đáng kể quá trình xử lý. Thay vào đó, việc dùng requests.Session() xuyên suốt quá trình xử lý 100K records sẽ tái sử dụng kết nối TCP. Điều này giúp giảm đáng kể độ trễ, đồng thời giảm tải cho cả client và server.
import requests
def process_records_efficiently(record_ids):
with requests.Session() as session:
# Có thể cấu hình session một lần ở đây (headers, auth, v.v.)
session.headers.update({
'Authorization': 'Bearer my_token',
'Content-Type': 'application/json'
})
for record_id in record_ids:
try:
# Sử dụng session để gửi yêu cầu
response = session.get(f'https://api.example.com/data/{record_id}', timeout=10)
response.raise_for_status()
print(f"Xử lý record {record_id} thành công.")
# Xử lý dữ liệu từ response.json()
except requests.exceptions.RequestException as e:
print(f"Lỗi khi xử lý record {record_id}: {e}")
# Ví dụ sử dụng (giả định có 100K record_ids)
# large_record_list = range(1, 100001)
# process_records_efficiently(large_record_list)
print("Đây là minh họa cách dùng Session để xử lý số lượng lớn records hiệu quả.")
Kiểm tra SSL Certificate (Xác minh chứng chỉ SSL)
Mặc định, requests sẽ xác minh chứng chỉ SSL cho các yêu cầu HTTPS. Điều này rất quan trọng cho bảo mật. Nếu bạn làm việc với các API tự host hoặc có chứng chỉ tự ký (self-signed certificate) trong môi trường phát triển, bạn có thể tắt xác minh bằng verify=False. Tuyệt đối không nên làm điều này trong môi trường production!
import requests
# response = requests.get('https://bad-ssl.example.com/', verify=True) # Mặc định là True
# Nếu gặp lỗi SSL trong môi trường phát triển và bạn chắc chắn về nguồn:
# response = requests.get('https://bad-ssl.example.com/', verify=False)
print("Lưu ý về verify SSL: Luôn để True trong môi trường production.")
Xử lý Rate Limiting (Giới hạn tỷ lệ yêu cầu)
Nhiều API áp đặt giới hạn số lượng yêu cầu bạn có thể gửi trong một khoảng thời gian nhất định (rate limiting), nhằm ngăn chặn lạm dụng. Nếu bạn gửi quá nhiều yêu cầu, API sẽ trả về lỗi 429 Too Many Requests. Hãy tôn trọng giới hạn này bằng cách thêm độ trễ (delay) giữa các yêu cầu hoặc sử dụng thư viện như tenacity để thử lại (retry) một cách thông minh.
import requests
import time
def fetch_data_with_rate_limit(urls):
for url in urls:
try:
response = requests.get(url)
if response.status_code == 429:
print("Gặp Rate Limit, chờ 60 giây...")
time.sleep(60) # Chờ một khoảng thời gian
# Sau đó có thể thử lại yêu cầu này
response = requests.get(url)
response.raise_for_status()
else:
response.raise_for_status()
print(f"Dữ liệu từ {url}: {response.json()['args']}") # Giả sử API httpbin.org/get
except requests.exceptions.RequestException as e:
print(f"Lỗi khi lấy dữ liệu từ {url}: {e}")
time.sleep(1) # Chờ 1 giây giữa các request để tránh rate limit
# Ví dụ
# api_urls = ['https://httpbin.org/get?item=1', 'https://httpbin.org/get?item=2']
# fetch_data_with_rate_limit(api_urls)
print("Minh họa cách xử lý Rate Limiting bằng time.sleep.")
Logging Requests và Responses
Trong quá trình debug hoặc phát triển, việc ghi nhật ký (logging) các yêu cầu và phản hồi HTTP là cực kỳ cần thiết. Bạn có thể cấu hình Python logging để hiển thị thông tin chi tiết từ thư viện requests.
import requests
import logging
# Bật logging cho thư viện requests
logging.basicConfig(level=logging.DEBUG)
#logging.getLogger("requests").setLevel(logging.DEBUG)
#logging.getLogger("urllib3").setLevel(logging.DEBUG)
# Gửi một yêu cầu
requests.get('https://httpbin.org/get')
print("\nKiểm tra output console để thấy log của requests.")
Kết luận
Thư viện requests của Python thực sự là công cụ không thể thiếu khi làm việc với API. Nó không chỉ giúp code của bạn gọn gàng, dễ đọc mà còn cung cấp các tính năng mạnh mẽ, xử lý hiệu quả hầu hết các tình huống giao tiếp web. Dù là gọi API cơ bản hay các tác vụ nâng cao như quản lý session, xử lý lỗi, xác thực và tối ưu hiệu suất, requests đều đáp ứng xuất sắc.
Áp dụng những kiến thức và kinh nghiệm mình đã chia sẻ, bạn hoàn toàn có thể tự tin xây dựng các ứng dụng Python tương tác hiệu quả và đáng tin cậy với các dịch vụ web. Hãy bắt đầu thực hành ngay để làm chủ công cụ tuyệt vời này nhé!
