Bài viết được sự cho phép của tác giả Nguyễn Việt Hưng
Python là một ngôn ngữ già, có thể bạn chưa biết, Python tuổi dê Python ra đời từ thời mới có HTTP, và nổi tiếng là hỗ trợ tận răng, nên không có gì lạ nếu Python có kèm sẵn thư viện standard để thực hiện HTTP request với tên urllib
.
Vậy nhưng khi lên mạng tìm kiếm hay hỏi quanh đây: dùng gì để gọi HTTP trong Python?, câu trả lời phần lớn đều là cài: pip install requests
.
Requests không phải có từ ngày Python xuất hiện, nhưng vào thời Python 2.6 2.7 (cỡ 2012-2013), requests đã rất phổ biến, ví dụ như câu trả lời trên StackOverFlow năm 2013.
Requests (có chữ s) xuất hiện với một API cực kỳ thân thiệt, với motto (khẩu hiệu): Python HTTP for Humans do urllib
có sẵn trong Python2 quá rắc rối. API của requests nổi tiếng đến mức gần như ngôn ngữ lập trình nào cũng có một thư viện “nhái” requests của Python, nó quá đơn giản, tới mức … trước đây không thư viện nào từng làm vậy.
(API của thư viện là các function mà thư viện đó public cho người dùng sử dụng, ví dụ requests có: requests.get, requests.post.)
Sau gần chục năm phát triển, requests
giờ đã nằm dưới mái nhà Python Software Foundation.
Với các tính năng được quảng cáo ở bản v1.0.0, cuối năm 2012
Có thể dễ đoán rằng những tính năng được quảng cáo trên chính là những gì urllib
Python thời đó chưa hỗ trợ (trong Python còn có cả thư viện tên urllib2
… để thêm phần phức tạp). Nhưng với Python 3.5 trở đi, rất nhiều trong số trên đã được hỗ trợ trong urllib
.
Còn đây là các tính năng được quảng cáo ở phiên bản mới nhất:
Nếu bạn đọc các tính năng này mà không hiểu gì, thì nó chỉ chứng minh một điều là HTTP là một giao thức rất lằng nhằng và phức tạp. Đáng kể nhất có:
- Browser-style SSL Verification: liên quan tới SSL – tức là bảo mật.
urllib
mãi tới Python 3.4.3 mới thực hiện kiểm tra SSL một cách mặc định:
- Connection Pooling: bình thường khi viết code truy cập vào 1 website, ta có thể nghĩ đơn giản là requests.get rồi lấy kết quả là xong chuyện, hết phiên. Nếu muốn truy cập trang khác cùng website đó, ta lại requests.get để truy cập mới. Phía dưới
requests.get
thực hiện tạo 1TCP connection
, sau đó mới gửiHTTP request
quaconnection
này. Việc tạo connection là công việc khá tốn kém (CPU, thời gian), đặc biệt với HTTPS, tạo SSL connection còn tốn hơn nhiều lần. Do vậy, để tăng hiệu năng, requests sẽ tự giữ lạiconnection
và dùng lại để truy cập website nếu như các yêu cầu sau đó cùng website, khác page. Xem code tại adapters.py.
Việc này ảnh hưởng tới hiệu năng, nhưng không ảnh hưởng gì nếu bạn chỉ gọi 1 request tới mỗi website.
Đọc code requests
Lib requests
thuộc loại nhỏ, tổng cộng 5000 dòng gồm rất nhiều comment. Nó tận dụng các thư viện ngoài khác thay vì tự làm tất cả: urllib3
để thực hiện connection pooling, thực hiện HTTP requests, dùng certifi
để cung cấp các SSL certificate mới nhất như các trình duyệt.
Phần API đơn giản lừng danh nằm trong file api.py
, trích bỏ comment:
urllib3
urllib3
là dependency quan trọng của requests
, nó đảm nhận những công việc nặng nề:
Thread safety.
Connection pooling.
Client-side SSL/TLS verification.
File uploads with multipart encoding.
Helpers for retrying requests and dealing with HTTP redirects.
Support for gzip and deflate encoding.
Proxy support for HTTP and SOCKS.
Code mẫu:
>>> import urllib3
>>> http = urllib3.PoolManager()
>>> r = http.request('GET', 'http://httpbin.org/robots.txt')
>>> r.status
200
>>> r.data
'User-agent: *nDisallow: /denyn'
urllib
urllib và urllib2 thời Python2.7 là những em gái dính lời nguyền mà ai cũng muốn tha thứ. Nhưng ở Python 3.6+, việc dùng urllib không còn quá phức tạp, hãy coi nó như 1 file, nhớ đóng file, hoặc dùng with
.
urllib đã kiểm tra SSL certificate
Kết quả tương tự khi dùng requests
do URL https://dantri.com
SSL certificate đẫ hết hạn Expire: January 19, 2020
>>> import requests
>>> requests.get("https://dantri.com")
Traceback (most recent call last):
File "/home/hvn/py3/lib/python3.6/site-packages/urllib3/connectionpool.py", line 672, in urlopen
...
File "/usr/lib/python3.6/ssl.py", line 689, in do_handshake
self._sslobj.do_handshake()
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:852)
urllib redirect ngon lành
>>> r = requests.get("https://gmail.com")
>>> r.url
'https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=https://mail.google.com/mail/&ss=1&scc=1<mpl=default<mplcache=2&emr=1&osid=1'
>>> from urllib.request import urlopen
>>> r = urlopen("https://gmail.com")
>>> r.url
'https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=https://mail.google.com/mail/&ss=1&scc=1<mpl=default<mplcache=2&emr=1&osid=1'
urllib với JSON API
Tra cứu thông tin COVID-19
Hành động của chúng ta
Có thể dùng urllib
khi script/chương trình chỉ truy cập mỗi website một lần, dùng trong các script ngắn, hay khi không tiện cài requests
. Nhớ sử dụng requests
Session khi truy cập 1 website nhiều lần để tăng hiệu năng.
Kết luận
Requests thành công vì sự đơn giản không thể hơn của nó, chứ không phải vì kỹ thuật cao siêu phức tạp.
Nhớ mặc định là dùng requests
, nhưng không bị sốc khi thấy người ta dùng urllib
.
Bài viết gốc được đăng tải tại pp.pymi.vn
Có thể bạn quan tâm:
- Là framework? Hay là library?
- Chuyện những Pull Requests trong lập trình
- [Python cơ bản thường dùng trong công việc] Phần 7 : Xử lý file JSON
Xem thêm Việc làm Developer hấp dẫn trên TopDev