Courses
Giao diện lập trình ứng dụng (API) là các trình trung gian phần mềm. Nhiệm vụ của chúng là cho phép các ứng dụng giao tiếp với nhau. Những trình trung gian tinh tế này xuất hiện trong đời sống hằng ngày dù bạn có để ý hay không. Ví dụ, nếu hôm nay bạn đã gửi một tin nhắn tức thời, bạn đã sử dụng một API.
Cụ thể hơn, API cho phép con người gửi và truy xuất dữ liệu bằng mã. Tuy vậy, việc sử dụng API để truy xuất dữ liệu là phổ biến hơn. Chẳng hạn, bạn có thể đọc bài viết này vì trình duyệt web của bạn đã lấy dữ liệu tạo nên trang này từ máy chủ DataCamp.
Nhưng máy chủ web không tự ý gửi dữ liệu ngẫu nhiên. Điều đó giống như vào nhà hàng và người bồi bàn mang ngẫu nhiên cho bạn một món ăn. Phải có một yêu cầu được gửi đến máy chủ để truy xuất dữ liệu trước khi máy chủ phản hồi dữ liệu. Điều này đúng cả với người bồi bàn trong nhà hàng, và nếu bạn muốn truy xuất dữ liệu từ một API, bạn gửi một yêu cầu API đến máy chủ, và nó sẽ phản hồi dữ liệu phù hợp.
Trong bài viết này, chúng ta sẽ cùng tìm hiểu một số thành phần cốt lõi của thư viện requests và cung cấp vài ví dụ mã để giúp bạn bắt đầu. Thư viện requests rất đáng để học vì đây là tiêu chuẩn de facto trong ngành để gửi các yêu cầu HTTP trong Python. Như bạn sẽ thấy, nó ẩn đi mọi thách thức của việc gửi yêu cầu đằng sau một API đơn giản, cho phép bạn tập trung vào giao tiếp với dịch vụ và tiêu thụ dữ liệu trong ứng dụng của mình.
Chạy và chỉnh sửa mã từ hướng dẫn trực tuyến này.
Chạy mãThực hiện yêu cầu GET và POST bằng mô-đun requests của Python
Đang vội? Đây là cú pháp Python để tạo một yêu cầu GET và POST đơn giản:
1. Yêu cầu GET
import requests
# The API endpoint
url = "https://jsonplaceholder.typicode.com/posts/1"
# A GET request to the API
response = requests.get(url)
# Print the response
print(response.json())
2. Yêu cầu POST
import requests
# The API endpoint
url = "https://jsonplaceholder.typicode.com/posts"
# Data to be sent
data = {
"userID": 1,
"title": "Making a POST request",
"body": "This is the data we created."
}
# A POST request to the API
response = requests.post(url, json=data)
# Print the response
print(response.json())
Tìm hiểu REST API và nền tảng HTTP của chúng
Chúng ta đã xác định API là các trình trung gian phần mềm. Cách khác để hình dung chúng là một dạng giao diện phần mềm cho phép các ứng dụng khác truy cập vào dữ liệu và phương thức cụ thể.
Một trong những kiến trúc phổ biến nhất để xây dựng API là mẫu REpresentational State Transfer (REST). Thiết kế kiến trúc REST cho phép client và server được triển khai độc lập với nhau và không cần biết về nhau. Điều này có nghĩa là mã ở mỗi bên có thể thay đổi mà không phải lo lắng thay đổi đó sẽ ảnh hưởng đến bên kia như thế nào.
Vì vậy, REST API tuân theo một bộ nguyên tắc được thiết kế để đơn giản hóa giao tiếp giữa phần mềm, nhờ đó quá trình truy cập dữ liệu trở nên dễ dàng và logic hơn. Đừng lo nếu bạn chưa biết các nguyên tắc này; bạn không cần biết chúng để bắt đầu – điều bạn cần biết là dữ liệu được REST service cung cấp ra sao.
Dữ liệu từ các dịch vụ web REST được đưa ra internet thông qua URL công khai, bạn có thể truy cập bằng cách gửi một yêu cầu HTTP.
Tổng quan về các phương thức yêu cầu HTTP
Quay lại ví dụ nhà hàng; để gọi món, người bồi bàn sẽ tiến đến, và bạn nói bạn muốn gì. Bồi bàn chuyển yêu cầu của bạn cho đầu bếp, người nấu món ăn rồi đưa lại cho bồi bàn để mang ra cho bạn. Nói cách khác, đầu bếp sẽ không nấu cho đến khi nhận được yêu cầu của bạn.
REST API cũng vậy: chúng lắng nghe các phương thức yêu cầu HTTP trước khi hành động. HTTP định nghĩa một tập hợp các phương thức yêu cầu để cho API biết cần thực hiện thao tác nào đối với một tài nguyên đã cho. Nó chỉ định cách tương tác với tài nguyên nằm tại endpoint được cung cấp.
Có nhiều phương thức HTTP, nhưng năm phương thức sau thường được dùng với REST API:
| Phương thức HTTP | Mô tả |
|---|---|
| GET | Truy xuất dữ liệu |
| POST | Tạo dữ liệu |
| PUT | Cập nhật dữ liệu hiện có |
| PATCH | Cập nhật một phần dữ liệu hiện có |
| DELETE | Xóa dữ liệu |
Rất có thể bạn sẽ thực hiện các yêu cầu GET nhiều hơn bất kỳ phương thức nào khác trong phân tích và khoa học dữ liệu. Bởi đây là phương thức cần thiết để truy cập một số tập dữ liệu. Tìm hiểu thêm trong khóa học Intermediate Importing Data in Python của DataCamp.
Khi bạn gửi yêu cầu đến máy chủ web, API sẽ trả về một phản hồi. Đính kèm phản hồi là một mã trạng thái HTTP. Mục đích của mã trạng thái là cung cấp thông tin bổ sung về phản hồi để client biết loại yêu cầu đã được nhận.
API endpoint là gì?
Một URL xác định dữ liệu bạn tương tác trên máy chủ web. Tương tự như URL trang web gắn với một trang duy nhất, URL endpoint liên kết với các tài nguyên cụ thể trong một API. Do đó, có thể mô tả endpoint là một vị trí số nơi API nhận các yêu cầu về tài nguyên cụ thể trên máy chủ của nó — hãy coi đó là đầu kia của kênh giao tiếp.
Để rõ hơn, REST API công bố một tập URL công khai mà các ứng dụng client có thể yêu cầu để truy cập tài nguyên của dịch vụ web. Các URL công khai do REST API cung cấp được gọi là “endpoint”.
Sử dụng Python để tạo yêu cầu HTTP
Mô-đun requests của Python cho phép nhà phát triển viết mã để tương tác với REST API. Nó cho phép gửi các yêu cầu HTTP bằng Python mà không phải lo những phức tạp thường có khi thực hiện các tác vụ như vậy (ví dụ: tự thêm query string vào URL, mã hóa biểu mẫu cho dữ liệu PUT và POST, v.v.).
Mặc dù được coi là tiêu chuẩn de facto để thực hiện yêu cầu HTTP trong Python, mô-đun requests không thuộc thư viện chuẩn của Python – bạn phải cài đặt nó.
Cách đơn giản nhất để cài đặt mô-đun requests là dùng pip:
python -m pip install requests
Luôn khuyến nghị quản lý các gói Python cho từng dự án bằng môi trường ảo; theo cách này, các gói của dự án này sẽ không can thiệp và làm hỏng công cụ hệ thống ở dự án khác vì chúng được tách biệt – thay vì cài đặt toàn cục.
Giờ chúng ta đã cài đặt mô-đun requests, hãy xem nó hoạt động như thế nào. Làm theo cùng với mã trong sổ tay DataLab này.
Thực hiện yêu cầu GET trong Python
Chúng ta đã xác định GET là một trong những phương thức yêu cầu HTTP phổ biến nhất khi làm việc với REST API. Nó cho phép bạn (client) truy xuất dữ liệu từ máy chủ web.
Lưu ý rằng GET là thao tác chỉ đọc, nghĩa là chỉ phù hợp để truy cập tài nguyên hiện có và không nên dùng để sửa đổi chúng.
Để minh họa cách mô-đun requests hoạt động, chúng ta sẽ dùng JSONPlaceholder, một API giả miễn phí cho mục đích thử nghiệm và tạo mẫu.
import requests
# The API endpoint
url = "https://jsonplaceholder.typicode.com/posts/1"
# A GET request to the API
response = requests.get(url)
# Print the response
response_json = response.json()
print(response_json)
"""
{'userId': 1, 'id': 1, 'title': 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit', 'body': 'quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto'}
"""
Trong đoạn mã trên, chúng ta đã thực hiện:
-
Xác định endpoint API để truy xuất dữ liệu.
-
Dùng phương thức
requests.get(url)để lấy dữ liệu từ endpoint đã xác định. -
Dùng phương thức
response.json()để lưu dữ liệu phản hồi vào một đối tượng dictionary; lưu ý điều này chỉ hoạt động vì kết quả ở định dạng JSON – nếu không sẽ phát sinh lỗi. -
Bước cuối là in dữ liệu phản hồi JSON.
Chúng ta cũng có thể kiểm tra mã trạng thái trả về từ API như sau:
# Print status code from original response (not JSON)
print(response.status_code)
"""
200
"""
Bạn cũng có thể truyền tham số vào yêu cầu GET trong Python. Để làm vậy, ta cần chỉnh sửa nhẹ đoạn mã trên. Dưới đây là mã mới:
# The API endpoint
url = "https://jsonplaceholder.typicode.com/posts/"
# Adding a payload
payload = {"id": [1, 2, 3], "userId":1}
# A get request to the API
response = requests.get(url, params=payload)
# Print the response
response_json = response.json()
for i in response_json:
print(i, "\n")
"""
{'userId': 1, 'id': 1, 'title': 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit', 'body': 'quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto'}
{'userId': 1, 'id': 2, 'title': 'qui est esse', 'body': 'est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla'}
{'userId': 1, 'id': 3, 'title': 'ea molestias quasi exercitationem repellat qui ipsa sit aut', 'body': 'et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut'}
"""
Khác biệt ở đây là:
-
Thay đổi endpoint API. Lưu ý cuối URL không còn
1. -
Xác định payload trong một dictionary.
-
Truyền payload vào đối số
paramcủa phương thứcrequests.get(). -
Kết quả trả về là một đối tượng list, vì vậy chúng ta lặp qua list và in từng phần tử trên một dòng mới.
Thực hiện yêu cầu POST trong Python
Các yêu cầu GET cho phép bạn truy xuất dữ liệu; các yêu cầu POST cho phép bạn tạo dữ liệu mới. Hãy xem cách chúng ta có thể tạo dữ liệu mới trên máy chủ JSONPlaceholder.
# Define new data to create
new_data = {
"userID": 1,
"id": 1,
"title": "Making a POST request",
"body": "This is the data we created."
}
# The API endpoint to communicate with
url_post = "https://jsonplaceholder.typicode.com/posts"
# A POST request to tthe API
post_response = requests.post(url_post, json=new_data)
# Print the response
post_response_json = post_response.json()
print(post_response_json)
"""
{'userID': 1, 'id': 101, 'title': 'Making a POST request', 'body': 'This is the data we created.'}
"""
Trong đoạn mã trên, chúng ta đã:
-
Tạo một tài nguyên mới mà chúng ta muốn thêm vào API JSONPlaceholder.
-
Xác định endpoint để
POSTdữ liệu mới. -
Gửi yêu cầu
POSTbằng phương thứcrequests.post(). Lưu ý tham sốjsonđược thiết lập trong phương thứcpost(); chúng ta làm vậy để cho API biết rõ rằng ta đang gửi một đối tượng JSON tới URL được chỉ định. -
Dùng phương thức
response.json()để lưu dữ liệu phản hồi vào một đối tượng dictionary. -
Bước cuối là in dữ liệu phản hồi JSON.
Nhưng, khoan đã!
Trước khi bạn đọc đoạn mã tiếp theo, hãy dành 20 giây để suy nghĩ mã trạng thái mà API sẽ trả về.
Nhớ nhé: lần này, chúng ta đã tạo một tài nguyên mới thay vì chỉ truy xuất nó.
Được rồi, đây là kết quả…
# Print status code from original response (not JSON)
print(post_response.status_code)
"""
201
"""
Các chủ đề nâng cao về yêu cầu HTTP trong Python
Tạo yêu cầu HTTP với Python thường khá đơn giản; tuy nhiên đôi khi không tránh khỏi việc cần cấu hình nâng cao hơn hoặc gặp sự cố. Dưới đây là một số thách thức bạn có thể gặp và cách giải quyết.
Xác thực các yêu cầu HTTP
Cho đến giờ, tương tác của chúng ta với REST API khá đơn giản. API JSONPlaceholder không yêu cầu bất kỳ xác thực nào để bạn bắt đầu tương tác. Tuy nhiên, có nhiều trường hợp REST API yêu cầu xác thực trước khi cho phép truy cập các endpoint cụ thể – đặc biệt khi bạn xử lý dữ liệu nhạy cảm.
Ví dụ, nếu bạn muốn tạo tích hợp, truy xuất dữ liệu và tự động hóa quy trình làm việc trên GitHub, bạn có thể làm điều đó với GitHub REST API. Tuy nhiên, có nhiều thao tác trên GitHub REST API yêu cầu xác thực, như truy xuất thông tin công khai và riêng tư về người dùng đã xác thực.
Dưới đây là một cách đơn giản dùng mô-đun requests của Python:
from requests.auth import HTTPBasicAuth
private_url = "https://api.github.com/user"
github_username = "username"
token = "token"
private_url_response = requests.get(
url=private_url,
auth=HTTPBasicAuth(github_username, token)
)
private_url_response.status_code
"""
200
"""
Trong đoạn mã trên, chúng ta:
-
Import đối tượng
HTTPBasicAuthtừrequests.auth. Đối tượng này gắn xác thực HTTP cơ bản vào đối tượng yêu cầu đã cho — về bản chất giống như bạn nhập tên người dùng và mật khẩu trên một trang web. -
Xác định endpoint URL riêng tư cần truy cập.
-
Khởi tạo một biến với tên người dùng GitHub – chúng tôi ẩn danh tên người dùng vì lý do riêng tư.
-
Khởi tạo một biến với personal access token của GitHub để xác thực.
-
Truy xuất dữ liệu từ endpoint và lưu trong biến
private_url_response. -
Hiển thị mã trạng thái.
Xử lý lỗi yêu cầu HTTP
Có những trường hợp yêu cầu gửi đến API không diễn ra như mong đợi. Có thể có nhiều yếu tố ở phía client hoặc server. Dù nguyên nhân là gì, kết cục vẫn như nhau: yêu cầu thất bại.
Khi dùng REST API, luôn là ý tưởng tốt để làm cho mã của bạn vững vàng. Tuy nhiên, trước khi có thể viết mã ổn định, bạn cần hiểu cách quản lý các lỗi được báo khi mọi thứ không theo kế hoạch.
Cho ví dụ này, hãy quay lại API JSONPlaceholder. Chúng ta sẽ bắt đầu bằng cách viết một đoạn mã rồi giải thích điều gì đang xảy ra.
# A deliberate typo is made in the endpoint "postz" instead of "posts"
url = "https://jsonplaceholder.typicode.com/postz"
# Attempt to GET data from provided endpoint
try:
response = requests.get(url)
response.raise_for_status()
# If the request fails (404) then print the error.
except requests.exceptions.HTTPError as error:
print(error)
"""
404 Client Error: Not Found for url: https://jsonplaceholder.typicode.com/postz
"""
Trong đoạn mã trên:
-
Chúng ta xác định endpoint JSONPlaceholder để truy xuất dữ liệu, nhưng cố ý gõ sai khi xây dựng URL – điều này sẽ tạo lỗi 404.
-
Chúng ta dùng xử lý ngoại lệ tích hợp của Python để
tryvàexcept(bắt) mọi lỗi phát sinh khi cố truy cập endpoint JSONPlaceholder. Lưu ý phương thứcraise_for_status()được dùng để trả về một đối tượngHTTPErrorkhi xảy ra lỗi trong quá trình này. -
Và cuối cùng, chúng ta in ra lỗi đã phát sinh.
Mặc dù ở đây chúng ta minh họa cách xử lý mã lỗi 404, cùng một khuôn mẫu có thể dùng để xử lý bất kỳ mã trạng thái HTTP nào.
Đối phó với quá nhiều chuyển hướng
Các mã trạng thái HTTP thuộc nhóm 3xx cho biết client đã bị chuyển hướng và phải thực hiện thêm một số thao tác để hoàn tất yêu cầu. Tuy nhiên, đôi khi điều này có thể dẫn đến vòng lặp chuyển hướng vô hạn.
Mô-đun requests của Python cung cấp đối tượng TooManyRedirects để xử lý vấn đề này như sau:
"""
Note: The code here will not raise an error
but the structure is how you would hand a case where there
are multiple redirects
"""
url = "https://jsonplaceholder.typicode.com/posts"
try:
response = requests.get(url)
response.raise_for_status()
except requests.exceptions.TooManyRedirects as error:
print(error)
Bạn cũng có thể đặt số lần chuyển hướng tối đa như một tham số của phương thức yêu cầu HTTP:
# Solution 2
url = "https://jsonplaceholder.typicode.com/posts"
session = requests.Session()
session.max_redirects = 3
response = session.get(url)
Một lựa chọn khác là vô hiệu hóa hoàn toàn chuyển hướng:
# Solution 3
url = "https://jsonplaceholder.typicode.com/posts"
session = requests.Session()
session.allow_redirects = False
response = session.get(url)
Xử lý lỗi kết nối trong các yêu cầu HTTP
Đây là những loại lỗi khác bạn có thể gặp khi cố gửi yêu cầu đến máy chủ. Có nhiều lý do khiến bạn không nhận được phản hồi từ máy chủ (ví dụ: lỗi DNS, bị từ chối kết nối, sự cố kết nối internet, v.v.), nhưng kết quả là như nhau: phát sinh lỗi kết nối.
Bạn có thể dùng đối tượng ngoại lệ ConnectionError của mô-đun requests để bắt các vấn đề này và xử lý phù hợp.
Mã có thể trông như sau:
"""
Note: The code here will not raise an error
but the structure is how you would hand a case where there
is a connection error.
"""
url = "https://jsonplaceholder.typicode.com/posts"
try:
response = requests.get(url)
except requests.ConnectionError as error:
print(error)
Xử lý timeout của yêu cầu HTTP
Khi máy chủ API chấp nhận kết nối của bạn nhưng không thể hoàn tất yêu cầu trong thời gian cho phép, bạn sẽ nhận được “lỗi timeout”.
Chúng ta sẽ minh họa cách xử lý trường hợp này bằng cách đặt tham số timeout trong phương thức requests.get() thành một con số cực nhỏ; điều này sẽ gây lỗi, và chúng ta sẽ xử lý lỗi đó bằng đối tượng requests.Timeout.
url = "https://jsonplaceholder.typicode.com/posts"
try:
response = requests.get(url, timeout=0.0001)
except requests.Timeout as error:
print(error)
Cách khắc phục đơn giản nhất cho lỗi timeout là đặt thời gian chờ dài hơn. Các giải pháp khác có thể gồm tối ưu hóa yêu cầu, thêm vòng lặp thử lại vào script, hoặc thực hiện các lời gọi API bất đồng bộ – một kỹ thuật cho phép phần mềm của bạn bắt đầu một hoạt động có thể kéo dài trong khi vẫn phản hồi với các sự kiện khác thay vì chờ đến khi tác vụ đó hoàn tất.
Tổng kết
Trong hướng dẫn này, chúng ta đã đề cập API là gì và khám phá một kiến trúc API phổ biến gọi là REST. Chúng ta cũng xem xét các phương thức HTTP và cách dùng thư viện requests của Python để tương tác với các dịch vụ web.
Hãy xem các khóa học sau để phát triển kỹ năng khoa học dữ liệu của bạn:
FAQs
Làm thế nào để xử lý custom header trong các yêu cầu HTTP của Python?
Bạn có thể thêm header tùy chỉnh vào yêu cầu HTTP bằng cách truyền một dictionary header vào tham số headers trong yêu cầu của bạn. Ví dụ:
import requests
url = "https://jsonplaceholder.typicode.com/posts"
headers = {
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "application/json"
}
response = requests.get(url, headers=headers)
print(response.json())
Lợi ích của việc dùng đối tượng session trong mô-đun requests là gì?
Việc sử dụng đối tượng Session trong mô-đun requests mang lại một số lợi ích, bao gồm:
- Kết nối liên tục: Duy trì kết nối qua nhiều yêu cầu, giúp cải thiện hiệu năng.
- Cài đặt toàn phiên: Cho phép bạn thiết lập header, cookie và tham số một lần cho mọi yêu cầu được tạo qua session.
- Giữ cookie: Tự động xử lý cookie, duy trì chúng qua các yêu cầu.
Ví dụ:
import requests
session = requests.Session()
session.headers.update({"Authorization": "Bearer YOUR_ACCESS_TOKEN"})
response = session.get("https://jsonplaceholder.typicode.com/posts")
print(response.json())
Làm thế nào để gửi tệp bằng yêu cầu POST trong Python?
Bạn có thể gửi tệp bằng yêu cầu POST bằng cách truyền một dictionary vào tham số files. Ví dụ:
import requests
url = "https://example.com/upload"
file_path = "/path/to/your/file.txt"
with open(file_path, 'rb') as file:
files = {'file': file}
response = requests.post(url, files=files)
print(response.status_code)
Làm thế nào để cấu hình mô-đun requests sử dụng proxy?
Bạn có thể cấu hình proxy trong mô-đun requests bằng cách truyền một dictionary vào tham số proxies. Ví dụ:
import requests
url = "https://jsonplaceholder.typicode.com/posts"
proxies = {
"http": "http://10.10.1.10:3128",
"https": "http://10.10.1.10:1080",
}
response = requests.get(url, proxies=proxies)
print(response.json())
Làm thế nào để xử lý timeout khi thực hiện yêu cầu HTTP với mô-đun requests của Python?
Bạn có thể xử lý timeout bằng cách chỉ định tham số timeout trong yêu cầu. Tham số này nhận giá trị tính bằng giây. Ví dụ:
import requests
url = "https://jsonplaceholder.typicode.com/posts"
try:
response = requests.get(url, timeout=5) # Timeout sau 5 giây
print(response.json())
except requests.Timeout:
print("Yêu cầu đã hết thời gian chờ")
