<jupyter_start><jupyter_text>Import des modules nécessaires<jupyter_code># Pour manipuler efficacement des tables de données dans Python
import pandas as pd

# Pour faire des requêtes GET et POST
import requests
print(pd.__version__)
print(requests.__version__)<jupyter_output>2.18.4<jupyter_text>Requêtage d'une API REST Pour lancer une requête GET, c'est ultra-simple : on utilise `requests.get(url)`.Si vous voulez glisser des paramètres avec la requête, utilisez l'argument optionnel `params`, qui accepte un simple dictionnaire.<jupyter_code>r = requests.get("https://data.angers.fr/api/records/1.0/search/",
                 params={
                     'dataset': 'horaires-theoriques-et-arrets-du-reseau-irigo-gtfs',
                     'rows': 10
                 })<jupyter_output><empty_output><jupyter_text>Regardons la nature de ce qui nous est renvoyé.<jupyter_code>type(r)<jupyter_output><empty_output><jupyter_text>C'est un objet de la classe `Response`. Si vous voulez connaitre toutes les méthodes attachées, faites `help(r)`<jupyter_code>help(r)<jupyter_output>Help on Response in module requests.models object:

class Response(builtins.object)
 |  The :class:`Response <Response>` object, which contains a
 |  server's response to an HTTP request.
 |  
 |  Methods defined here:
 |  
 |  __bool__(self)
 |      Returns True if :attr:`status_code` is less than 400.
 |      
 |      This attribute checks if the status code of the response is between
 |      400 and 600 to see if there was a client error or a server error. If
 |      the status code, is between 200 and 400, this will return True. This
 |      is **not** a check to see if the response code is ``200 OK``.
 |  
 |  __enter__(self)
 |  
 |  __exit__(self, *args)
 |  
 |  __getstate__(self)
 |  
 |  __init__(self)
 |      Initialize self.  See help(type(self)) for accurate signature.
 |  
 |  __iter__(self)
 |      Allows you to use a response as an iterator.
 |  
 |  __nonzero__(self)
 |      Returns True if :attr:`status_code` is less than 400.
 |      
 |      This attribute checks if[...]<jupyter_text>Pour tester que tout a bien fonctionnné, on va vérifié le statut.<jupyter_code>r.raise_for_status()<jupyter_output><empty_output><jupyter_text>Si ça dit rien c'est que c'est bon :) Dans le doute, regardons le statut...<jupyter_code>r.status_code<jupyter_output><empty_output><jupyter_text>Statut 200 = succès !! Pour récupérer le contenu de la réponse, vous pouvez utiliser `r.text`.Il y a aussi un décodeur JSON, si on sait que la réponse est dans ce format. Du coup, il parse le JSON et rend un dictionnaire !<jupyter_code>r.json()<jupyter_output><empty_output><jupyter_text>Remplissage de DataFrame On peut construire une `DataFrame` directement à partir d'un "dictionnaires de colonnes".<jupyter_code>df = pd.DataFrame({
    'a': [1, 2, 3],
    'b': [3, 4, 1]
})

df<jupyter_output><empty_output><jupyter_text>Par exemple, listons les arrêts, leur id, leur nom et leurs coordonnées GPS.<jupyter_code>dd = r.json()['records']
dd[0]
ids = [elem['fields']['stop_id'] for elem in dd]
names = [elem['fields']['stop_name'] for elem in dd]
lats = [elem['fields']['stop_coordinates'][0] for elem in dd]
lons = [elem['fields']['stop_coordinates'][1] for elem in dd]

df = pd.DataFrame({
    'id': ids,
    'name': names,
    'latitude': lats,
    'longitude': lons
})

df<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11245216367382985, 'fraction_numerical': 0.012069473064468648, 'mean_word_length': 4.0944527736131935, 'pattern_counts': {'":': 0, '<': 36, '<?xml version=': 0, '>': 36, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '361975', 'license': 'MIT', 'n_tokens_mistral': 1190, 'n_tokens_neox': 1150, 'n_words': 348, 'path': 'tutoriels/requests-and-data-models.ipynb', 'repo_name': 'girardea/cours-data', 'size': '3397'}