When writing a software package (library), a well-designed API is as important as the functionality of the package (if, of course, you want to be used by others), what is the standard of a good API? In this article, I will compare the differences between the Requests library and the Urllib library (which belongs to the Python Standard library) in some typical HTTP usage scenarios, and publish some of the author's views, and discuss why the Requests library becomes the actual standard library in the Python user base 。
In the next discussion we will use Python 3.5 and Requests 2.10.0.
This article was adapted from my speech at the local Python party last week. The reader can find the slides of the speech here.
Requests and Urllib
Use Case 1: send a GET request
Import Urllib.request
Urllib.request.urlopen (' http://python.org/')
Import requests
Requests.get (' http://python.org/')
<response [200]>
Explicit (API endpoint) superior to obscure
Requests libraries send requests for more concise purposes (and therefore clearer)
The Urllib library sends a GET request without omitting the data parameter, which is more obscure
The function name of the Requests library clearly explains the purpose of the function
Useful Object Notation
As the reader observes, the Requests library returns a string containing the request status code (which is implemented through the __REPR () __ method)
The Urllib library returns only the default (Fuzzy) object representation
Code fragment
requests/api.py:
Def request (method, URL, **kwargs):
With sessions. Session () as session:
Return Session.request (Method=method, Url=url, **kwargs)
def get (URL, Params=none, **kwargs):
Kwargs.setdefault (' allow_redirects ', True)
Return request (' Get ', url, params=params, **kwargs)
def post (URL, Data=none, Json=none, **kwargs):
Return request (' post ', URL, Data=data, Json=json, **kwargs)
All HTTP actions have a similar process before they are sent, so a request () function is implemented as the main process control function.
All HTTP actions have a corresponding "auxiliary function", and then call the request () function in the helper function, which makes our function calls more explicit.
Use Case 2: Get the request status code
Import Urllib.request
r = Urllib.request.urlopen (' http://python.org/')
R.getcode ()
200
Import requests
r = Requests.get (' http://python.org/')
R.status_code
200
No need for getters and setters.
Getting the attributes of an object by reading the property, rather than by invoking the method, can make the code clearer.
If the reader is exposed to other object-oriented languages (such as Java), you may be able to modify the object's properties by setting getters and setters. This is not necessary in Python, and readers can accomplish this only by using @property adorners.
Code fragment
http/client.py:
Class HttpResponse (IO. Bufferediobase):
# ...
def getcode (self):
Return Self.status
Urllib Library (or HTTP) returns the properties of a class with an "getter" method
Use Case 3: Encode, send, and decode POST requests
Import Urllib.parse
Import Urllib.request
Import JSON
url = ' Http://www.httpbin.org/post '
Values = {' name ': ' Michael Foord '}
data = Urllib.parse.urlencode (values). Encode ()
Response = Urllib.request.urlopen (URL, data)
BODY = Response.read (). Decode ()
Json.loads (body)
Import requests
url = ' Http://www.httpbin.org/post '
data = {' name ': ' Michael Foord '}
Response = Requests.post (URL, data=data)
Response.json ()
Common features to be easy to use
The Requests library provides a preset way to encode data and parse JSON responses, but readers need to implement these methods themselves when using the Urllib library.
When designing APIs, readers need to think: what is the main purpose of the package? What interfaces can be added that can be more easily met for these purposes?
Similarly, the Requests library provides an elegant way to send JSON data:
Import requests
url = ' Http://www.httpbin.org/post '
data = {' name ': ' Michael Foord '}
Response = Requests.post (URL, json=data)
Response.json ()
Use case 4: send a validated request
The following code completes a long-term authentication for HTTP requests and sends a request:
Import Urllib.request
Gh_url = ' Https://api.github.com/user '
Password_mgr = Urllib.request.HTTPPasswordMgrWithDefaultRealm ()
Password_mgr.add_password (None, Gh_url, ' user ', ' pswd ')
Handler = Urllib.request.HTTPBasicAuthHandler (password_mgr)
Opener = Urllib.request.build_opener (handler)
Opener.open (Gh_url)
Import requests
Session = requests. Session ()
Session.auth = (' user ', ' pswd ')
Session.get (' Https://api.github.com/user ')
But what if we just need to complete one HTTP request? Do you need so much code? Using the Requests library requires only the following code to complete:
Import requests
Requests.get (' Https://api.github.com/user ', auth= (' user ', ' pswd '))
Contains both simple and advanced usage
The Requests library has both a simple use to send a single request and a complex use to send multiple requests.
Do not allow users to complete simple tasks also need to go through a lengthy process.
Try to use Python's built-in data structure instead of creating new data structures
The Requests library uses Python's built-in data structure, which makes it very easy to use. Users do not need to understand the structure inside the Requests library.
Library code
requests/models.py
def prepare_auth (self, auth, url= "):
"" "Prepares the given HTTP auth data." "
# ...
If Auth:
If Isinstance (auth, tuple) and Len (auth) = 2:
# special-case Basic HTTP Auth
Auth = Httpbasicauth (*auth)
The Requests library converts (user, pass) tuples internally into an authentication class
Use case 5: Handling Errors
From urllib.request import Urlopen
Response = Urlopen (' Http://www.httpbin.org/geta ')
Response.getcode ()
---------------------------------------------------------------------------
Httperror Traceback (most recent call last)
<ipython-input-45-5fba039d189a> in <module> ()
1 from urllib.request import Urlopen
----> 2 response = Urlopen (' Http://www.httpbin.org/geta ')
3 Response.getcode ()
/usr/lib/python3.5/urllib/request.py in Urlopen (URLs, data, timeout, Cafile, Capath, Cadefault, context)
161 Else:
162 opener = _opener
--> 163 return Opener.open (URL, data, timeout)
164
165 def Install_opener (opener):
/usr/lib/python3.5/urllib/request.py in open (self, fullurl, data, timeout)
470 for processor in Self.process_response.get (protocol, []):
471 meth = getattr (processor, Meth_name)
--> 472 response = Meth ( Req, response)
473
474 Return response
/usr/lib/python3.5/urllib/request.py in Http_response (self, request, response)
580 if not (<= code < $):
581 response = Self.parent.error (
--> 582 ' http ', request , response, Code, MSG, HDRs)
583
584 return response
/usr/lib/python3.5/urllib/request.py in error (self, proto, *args)
508 if Http_err:
509 args = (dict, ' Default ', ' Http_error_default ') + Orig_args
--> 510 & nbsp; return Self._call_chain (*args)
511
# XXX probably also want an abstract factory this knows when it makes
/usr/lib/python3.5/urllib/request.py in _call_chain (self, chain, kind, Meth_name, *args)
442 for handler in handlers:
443 & nbsp; func = getattr (Handler, meth_name)
--> 444 result = Func (*args)
445 if not None:
& nbsp; 446 return result
/usr/lib/python3.5/urllib/request.py in Http_error_default (self, req, FP, code, MSG, HDRs)
588 class Httpdefaulterrorhandler (Basehandler):
589 def http_error_default (self, req, FP, code, MSG, HDRs):
--> 590 Raise Httperror (Req.full_url, Code, MSG, HDRs, FP)
591
592 class Httpredirecthandler (Basehandler):
Httperror:http Error 404:not FOUND
Import requests
r = Requests.get (' Http://www.httpbin.org/geta ')
R.status_code
404
Let the user choose how to handle the error
Some programmers tend to handle errors in an unusual way, while others tend to handle errors in a way that is checked.
Some scenes are more elegant, while others are the opposite.
It is reasonable to allow the user to choose how to handle the error.
The default return error code can implement the reasonable approach described above, and the default exception handling error is not possible.
Case:
From urllib.request import Urlopen
From Urllib.error import Urlerror, Httperror
Try
Response = Urlopen (' Http://www.httpbin.org/geta ')
Except Httperror as E:
If E.code = 404:
Print (' Page not found ')
Else
Print (' All good ')
Page not found
From requests.exceptions import Httperror
Import requests
r = Requests.get (' Http://www.httpbin.org/posta ')
Try
R.raise_for_status ()
Except Httperror as E:
If E.response.status_code = 404:
Print (' Page not found ')
Page not found
Import requests
r = Requests.get (' Http://www.httpbin.org/geta ')
If R.ok:
Print (' All good ')
elif R.status_code = = Requests.codes.not_found:
Print (' Page not found ')
Page not found
The above is the full contents of this article. In preparing this speech and this article process, the author harvest quite abundant, also hoped that the reader can also have the harvest in the reading process. Readers can advise me by commenting on the comments below the post or on Twitter (@noamelf), and I am very happy to listen to these suggestions