Aujourd'hui, le web a prit une place importante dans notre vie de tous les jours.
Que ce soit pour lire ses mails, lire les actualités, consulter la météo, se documenter, jouer, bref la liste est longue et non exhaustive.
Python permet de faire différents types de requêtes sur le web.
Pour ce faire, Python propose le module urllib3.
Ce module est très complet et par conséquent un peu complexe à utiliser.
Le module requests, qui utilise toute la puissance du module urllib3 est beaucoup plus simple d'utilisation et énormément utilisé pour interagir avec le web.
Comme un petit exemple vaut mieux qu'un long discours...
>>> import requests
>>> html = requests.get('https://www.python.org/downloads/')
>>> html.status_code
200
>>> html.url
'https://www.python.org/downloads/'
>>> html.raw
<urllib3.response.HTTPResponse object at 0x0B80D6D0>
>>> html.encoding
'utf-8'
>>> html.headers
{'Server': 'nginx', 'Content-Type': 'text/html; charset=utf-8', 'X-Frame-Options': 'DENY', 'Cache-Control': 'max-age=604800, public', 'Via': '1.1 vegur, 1.1 varnish, 1.1 varnish', 'Content-Length': '113054', 'Accept-Ranges': 'bytes', 'Date': 'Thu, 06 Jun 2019 13:08:10 GMT', 'Age': '132076', 'Connection': 'keep-alive', 'X-Served-By': 'cache-iad2130-IAD, cache-cdg20735-CDG', 'X-Cache': 'HIT, HIT', 'X-Cache-Hits': '1, 5', 'X-Timer': 'S1559826490.039199,VS0,VE1', 'Strict-Transport-Security': 'max-age=63072000; includeSubDomains'}
>>> html.is_redirect
False
Voici donc un exemple d'une requête "GET" et des différentes informations que nous obtenons (dans l'ordre):
- Le statut de la requête (ici 200, indiquant que la requête s'est bien déroulée)
- L'url requêtée
- Le format brut de notre requête (on voit qu'il s'agit d'un objet HTTPResponse du module urllib3)
- De l'encodage utilisé (ici, UTF-8)
- Tout le contenu de l'en-tête
- Si la requête effectuée est une redirection
Mais une des choses les plus importantes est quand même le contenu de la requête....
>>> len(html.content)
113054
>>> html.content[:500]
b'<!doctype html>\n<!--[if lt IE 7]> <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9"> <![endif]-->\n<!--[if IE 7]> <html class="no-js ie7 lt-ie8 lt-ie9"> <![endif]-->\n<!--[if IE 8]> <html class="no-js ie8 lt-ie9"> <![endif]-->\n<!--[if gt IE 8]><!--><html class="no-js" lang="en" dir="ltr"> <!--<![endif]-->\n\n<head>\n <meta charset="utf-8">\n <meta http-equiv="X-UA-Compatible" content="IE=edge">\n\n <link rel="prefetch" href="//ajax.googleapis.com/ajax/libs/jqu'
>>> html.content[-500:]
b'ncludes.js"></script>\n\n <script type="text/javascript" src="/static/js/main-min.fbfe252506ae.js" charset="utf-8"></script>\n \n\n <!--[if lte IE 7]>\n <script type="text/javascript" src="/static/js/plugins/IE8-min.16868e6a5d2f.js" charset="utf-8"></script>\n \n \n <![endif]-->\n\n <!--[if lte IE 8]>\n <script type="text/javascript" src="/static/js/plugins/getComputedStyle-min.c3860be1d290.js" charset="utf-8"></script>\n \n \n <![endif]-->\n\n \n\n \n \n\n</body>\n</html>\n'
J'affiche les 500 premiers/derniers caractères du contenu de la requête qui en contient au total 113054.
Nous voilà donc avec tout le contenu de la page https://www.python.org/downloads/.
Si les données de la requête sont au format JSON, très courant dans le monde des APIs et des WebServices.
L'objet retourné par request contient une méthode json qui permet de formater le contenu en JSON si celui-ci est reconnu comme tel.
Par exemple, avec la liste des codes postaux...
>>> req = requests.get('https://unpkg.com/codes-postaux@3.2.0/codes-postaux.json')
>>> req.status_code
200
>>> json = req.json()
>>> type(json)
<class 'list'>
>>> len(json)
35728
>>> pprint(json[:5])
[{'codeCommune': '01001',
'codePostal': '01400',
'libelleAcheminement': "L'ABERGEMENT-CLEMENCIAT",
'nomCommune': "L'Abergement-Clémenciat"},
{'codeCommune': '01002',
'codePostal': '01640',
'libelleAcheminement': 'ABERGEMENT-DE-VAREY (L )',
'nomCommune': "L'Abergement-de-Varey"},
{'codeCommune': '01004',
'codePostal': '01500',
'libelleAcheminement': 'AMBERIEU-EN-BUGEY',
'nomCommune': 'Ambérieu-en-Bugey'},
{'codeCommune': '01005',
'codePostal': '01330',
'libelleAcheminement': 'AMBERIEUX-EN-DOMBES',
'nomCommune': 'Ambérieux-en-Dombes'},
{'codeCommune': '01006',
'codePostal': '01300',
'libelleAcheminement': 'AMBLEON',
'nomCommune': 'Ambléon'}]
Quoi de plus simple.
Si une authentification HTTP basique est nécessaire, il est possible de passer le nom d'utilisateur et le mot de passe lors de l'exécution de la requête.
>>> req = requests.get('https://unpkg.com/codes-postaux@3.2.0/codes-postaux.json', auth=('username','password'))
>>> req.status_code
200
>>> req.request.headers
{'User-Agent': 'python-requests/2.22.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Authorization': 'Basic dXNlcm5hbWU6cGFzc3dvcmQ='}
>>> import base64
>>> base64.b64decode(req.request.headers.get('Authorization').split(' ')[1])
b'username:password'
En examinant l'en-tête de la requête, on s'aperçoit qu'une clé 'Authorization' a été ajouté, que le type est 'Basic' et le contenu, nom d'utilisateur et mot de passe, sont encodés en base64.
Si on décode le contenu à l'aide du module base64, on récupère les informations d'authentification.
D'autres méthodes d'authentification sont diponibles, tout est expliqué ici.
Pour finir, il est également possible d'utiliser une session pour effectuer plusieurs requêtes sur un site, ce qui permet de conserver les informations d'identification et les cookies pendant l'exécution de toutes les requêtes.
>>> sess = requests.Session()
>>> req = sess.get('https://unpkg.com/codes-postaux@3.2.0/codes-postaux.json')
>>> req.status_code
200
A vous de jouer.