urllib
in some typical HTTP usage scenarios. Requests
so popular and easy to use.Disclaimer: Urllib was developed almost a decade earlier with a different set of language tools and requirements in mind.
This is an interactive talk.
import urllib.request
urllib.request.urlopen('http://python.org/')
<http.client.HTTPResponse at 0x7fa2b7183ef0>
import requests
requests.get('http://python.org/')
<Response [200]>
# ...
from . import utils
from .models import Request, Response, PreparedRequest
from .api import request, get, head, post, patch, put, delete, options
from .sessions import session, Session
from .status_codes import codes
from .exceptions import (
RequestException, Timeout, URLRequired,
TooManyRedirects, HTTPError, ConnectionError,
FileModeWarning,
)
# ...
requests.get
.urllib.request.urlopen
. It produce a GET request since it didn't receive a data
argument.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)
<Response [200]>
# vs.
<http.client.HTTPResponse at 0x7fa2b7183ef0>
__repr__
is a great idea, use it! and when you do, think what are the most significant attributes of the object to present. class Response(object):
# ...
def __repr__(self):
return '<Response [%s]>' % (self.status_code)
import urllib.request
response = urllib.request.urlopen('http://python.org/')
response.getcode()
import requests
r = requests.get('http://python.org/')
r.status_code
class HTTPResponse(io.BufferedIOBase):
# ...
def getcode(self):
return self.status
@property
decorator enables just that, but in a gradual way.@property
existed. class Response(object):
# ---
@property
def ok(self):
try:
self.raise_for_status()
except HTTPError:
return False
return True
from urllib.request import urlopen
urlopen('http://www.httpbin.org/status/400')
--------------------------------------------------------------------------- HTTPError Traceback (most recent call last) <ipython-input-10-f489128345a6> in <module>() 1 from urllib.request import urlopen ----> 2 response = urlopen('http://www.httpbin.org/status/400') 3 response.getcode() /usr/lib/python3.5/urllib/request.py in urlopen(url, 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 (200 <= code < 300): 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 return self._call_chain(*args) 511 512 # XXX probably also want an abstract factory that 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 func = getattr(handler, meth_name) --> 444 result = func(*args) 445 if result is not None: 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 400: BAD REQUEST
import requests
requests.get('http://www.httpbin.org/status/400')
<Response [400]>
With requests you can choose to raise an exception:
import requests
r = requests.get('http://www.httpbin.org/status/400')
r.raise_for_status()
--------------------------------------------------------------------------- HTTPError Traceback (most recent call last) <ipython-input-5-7e2ad828dd53> in <module>() 1 import requests 2 r = requests.get('http://www.httpbin.org/geta') ----> 3 r.raise_for_status() ~/.virtualenvs/py-api-talk/lib/python3.5/site-packages/requests/models.py in raise_for_status(self) 927 928 if http_error_msg: --> 929 raise HTTPError(http_error_msg, response=self) 930 931 def close(self): HTTPError: 404 Client Error: NOT FOUND for url: http://www.httpbin.org/geta
Or, handle the error without one:
import requests
r = requests.get('http://www.httpbin.org/status/400')
if r.ok:
print('Success!')
exceptions
do not.import urllib.parse
import urllib.request
import json
url = 'http://www.httpbin.org/post'
values = {'name' : 'Michael Foord'}
data = urllib.parse.urlencode(values).encode()
# -> b'name=Michael+Foord'
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()
On the same note, requests
also provides an elegant way to send JSON
content:
import requests
url = 'http://www.httpbin.org/post'
data = {'name' : 'Michael Foord'}
requests.post(url, json=data)
<Response [200]>
import urllib.request
url = 'http://www.httpbin.org/basic-auth/user/pswd'
password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
password_mgr.add_password(None, url, 'user', 'pswd')
handler = urllib.request.HTTPBasicAuthHandler(password_mgr)
opener = urllib.request.build_opener(handler)
opener.open(url)
import requests
url = 'http://www.httpbin.org/basic-auth/user/pswd'
# Creating a persistent auth for all the requests
session = requests.Session()
session.auth = ('user', 'pswd')
session.get(url)
# Or just for a single request:
requests.get(url, auth=('user', 'pswd'))
class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
# ...
def prepare_auth(self, auth, url=''):
# ...
if auth:
if isinstance(auth, tuple) and len(auth) == 2:
# special-case basic HTTP auth
auth = HTTPBasicAuth(*auth)
requests
internally converts the (user,pass)
tuple to an authentication class.