<jupyter_start><jupyter_text>Rappel - Fonctionnement d'un carnet web iPython* Pour exécuter le code contenu dans une cellule d'un carnet iPython, cliquez dans la cellule et faites (⇧↵, shift-enter) * Le code d'un carnet iPython s'exécute séquentiellement de haut en bas de la page. Souvent, l'importation d'une bibliothèque Python ou l'initialisation d'une variable est préalable à l'exécution d'une cellule située plus bas. Il est donc recommandé d'exécuter les cellules en séquence. Enfin, méfiez-vous des retours en arrière qui peuvent réinitialiser certaines variables.  Interrogation d'un service Web (IPA à base de ressources) Les marées des sept prochains jours à Tadoussac Vous planifiez une sortie en kayak de mer à Tadoussac qui est située sur le fleuve Saint-Laurent à l'embouchure du Saguenay. Vous allez moissonner les informations concernant les marées pour les sept prochains jours à compter du 21 septembre 2021. Pour cela, vous utiliserez un nouveau service web avec une interface de programmation à base de ressources (en anglais, REST API) disponible depuis peu sur le site de Pêches et Océans Canada. Pour les requêtes HTTP avec le site web, vous utiliserez la bibliothèque python urllib.request. L'extraction des sections pertinentes de la page web des résultats sera faite avec l'outil python Beautiful Soup. Enfin, des expressions régulières2 seront utilisées pour extraire les informations détaillées.1Note - documentation: La documentation sur le service web avec une interface de programmation à base de ressources (en anglais, REST API).2Note - pratique: regex101.com est un excellent site pour pratiquer et mettre au point des expressions régulières.  Importation des bibliothèques Python    urllib (interface client de haut niveau pour HTTP) et re (expressions régulières), json (traitement du format de données json: JavaScript Object Notation) et et datetime (traitement des dates et de l'heure) sont des bibliothèques Python standard, vous n'avez pas besoin de les installer, il suffit de les importer.  Installation de Beautiful Soup      Par exemple, sudo pip3 install bs4<jupyter_code># -*- coding: utf-8 -*-
import urllib.request
# sudo pip3 install bs4
from bs4 import BeautifulSoup
import json
import re
import datetime

print("Bibliothèques Python importées")<jupyter_output><empty_output><jupyter_text>Consultation de la documentation l'IPA à base de ressources1La documentation sur l'IPA donne un exemple de requête qui vous servira d'inspiration. Exemple :            Pour trouver les identifiants (ID) de vos stations d’intérêts : https://api-iwls.dfo-mpo.gc.ca/api/v1/stations.        Utiliser la requête suivante pour obtenir les niveaux d’eau officiels (wlo) pour la station Vieux-Québec (ID code : 5cebf1e23d0f4a073c4bc0f6) du 1er au 2 octobre 2020 : https://api-iwls.dfo-mpo.gc.ca/api/v1/stations/5cebf1e23d0f4a073c4bc0f6/data?time-series-code=wlo&from=2020-10-01T00:00:00Z&to=2020-10-01T00:30:00Z        [{"eventDate":"2020-10-01T00:00:00Z","qcFlagCode":"1","value":3.903,"timeSeriesId":"5cebf1e23d0f4a073c4bc0e1","reviewed":true},{"eventDate":"2020-10-01T00:03:00Z","qcFlagCode":"1","value":3.865,"timeSeriesId":"5cebf1e23d0f4a073c4bc0e1","reviewed":true},{"eventDate":"2020-10-01T00:06:00Z","qcFlagCode":"1","value":3.825,"timeSeriesId":"5cebf1e23d0f4a073c4bc0e1","reviewed":true},{"eventDate":"2020-10-01T00:09:00Z","qcFlagCode":"1","value":3.784,"timeSeriesId":"5cebf1e23d0f4a073c4bc0e1","reviewed":true},{"eventDate":"2020-10-01T00:12:00Z","qcFlagCode":"1","value":3.743,"timeSeriesId":"5cebf1e23d0f4a073c4bc0e1","reviewed":true},{"eventDate":"2020-10-01T00:15:00Z","qcFlagCode":"1","value":3.7,"timeSeriesId":"5cebf1e23d0f4a073c4bc0e1","reviewed":true},{"eventDate":"2020-10-01T00:18:00Z","qcFlagCode":"1","value":3.661,"timeSeriesId":"5cebf1e23d0f4a073c4bc0e1","reviewed":true},{"eventDate":"2020-10-01T00:21:00Z","qcFlagCode":"1","value":3.62,"timeSeriesId":"5cebf1e23d0f4a073c4bc0e1","reviewed":true},{"eventDate":"2020-10-01T00:24:00Z","qcFlagCode":"1","value":3.578,"timeSeriesId":"5cebf1e23d0f4a073c4bc0e1","reviewed":true},{"eventDate":"2020-10-01T00:27:00Z","qcFlagCode":"1","value":3.538,"timeSeriesId":"5cebf1e23d0f4a073c4bc0e1","reviewed":true},{"eventDate":"2020-10-01T00:30:00Z","qcFlagCode":"1","value":3.495,"timeSeriesId":"5cebf1e23d0f4a073c4bc0e1","reviewed":true}]Remplacer l’ID de la station “5cebf1e23d0f4a073c4bc0f6” par celui de votre station d’intérêt;        Changer la valeur du paramètre “Time-series-code” pour utiliser soit :                                    wlo – Niveau d’eau observé                wlf ou wlf-spine – Prévisions des niveaux d’eau (aux stations opérationnelles seulement)                wlp – Niveaux d’eau prédits aux 15 minutes                wlp-hilo – Prédictions des hautes et basses mers (Tables de marées)                Ajuster la période de temps “From” et “To” en utilisant le format ISO 8061 UTC.                            Il suffit donc de remplacer l'id_station par celui de Tadoussac et le code de la série chonologique 'wlo' (water level official)  par celui des marées "wlp-hilo".Les dates iront du 21 septembre 2021 00:00:00 (soit 0 heure, 0 min, 0 sec) au matin du 28 septembre 2021 à 00:00:00 mais en heure avancée de l'Est (HAE) utilisée au Québec en septembre. Par contre, le temps du service des marées est donné en temps universel (TU). Il faut donc convertir l'heure avancée de l'Est (HAE) utilisée au Québec en temps universel (TU) en ajoutant 4 heures. Donc 00:00:00 HAE à Tadoussac fera 04:00:00 en temps universel (TU). Inversement pour convertir le temps universel (TU) des résultats retournées en heure avancée de l'Est (HAE), il faudra soustraire 4 heures. 1Note - documentation: La documentation sur le service web avec une interface de programmation à base de ressources (en anglais, REST API).  Programmation d'une requête pour obtenir l'horaire des marées du service Web  Trouver l'identifiant de la station pour la municipalité de "Tadoussac"Appeler le service pour obtenir les stations et examiner de la page retournée"<jupyter_code># Obtenir l'IPA à base de ressources de Pêches et Océans
service_web = "https://api-iwls.dfo-mpo.gc.ca/api/v1/"

# Requête pour obtenir la liste des stations
requete = "stations"

with urllib.request.urlopen(service_web+requete) as response:
    page_reponse = response.read()

# Analyser la page de réponse retournée avec BeautifulSoup
dom_page_resultats = BeautifulSoup(page_reponse,"html.parser") 
# Afficher la page web retournée
print(dom_page_resultats.prettify())<jupyter_output><empty_output><jupyter_text>Extraction de l'identifiant et du code de la stationDans le code HTML de la page, on retrouve la section contenant le mot «Tadoussac». On en examine un bout pour en extraire le contenu en utilisant une expression régulière. `{"id":"5cebf1df3d0f4a073c4bbbaf","code":"03425","officialName":"Tadoussac"`Évidemment pour faire un simple test, on pourrait se contenter d'extraire l'identifiant (5cebf1df3d0f4a073c4bbbaf) manuellement. L'extraction par programmation au moyen d'une expression régulière permettra d'automatiser la tâche pour une éventuelle réutilisation. Voir la documentation française sur les expressions régulières en Python. Aidez-vous du site regex101.com pour mettre au point votre expression régulière.<jupyter_code>municipalite_requise = "Tadoussac"

FORME = re.compile(r'"id":"([\w|\d]*)","code":"(\d*)","officialName":"'+municipalite_requise)
formes_reconnues = re.search(FORME,dom_page_resultats.get_text())
if formes_reconnues:
    id_station = formes_reconnues.group(1)
    code_station = formes_reconnues.group(2)
print("id_station:",id_station)
print("code_station:",code_station)<jupyter_output><empty_output><jupyter_text>Programmation de la requête pour obtenir l'horaire des maréesVous construisez la requête en modifiant l'exemple `https://api-iwls.dfo-mpo.gc.ca/api/v1/stations/5cebf1e23d0f4a073c4bc0f6/data?time-series-code=wlo&from=2020-10-01T00:00:00Z&to=2020-10-01T00:30:00Z`<jupyter_code>service_web = "https://api-iwls.dfo-mpo.gc.ca/api/v1/"

id_station = "5cebf1df3d0f4a073c4bbbaf"
date_requise_debut = "2021-09-21"
heure_requise_debut = "04:00:00"
date_requise_fin = "2021-09-28"
heure_requise_fin = "04:00:00"

requete = "stations/" + id_station + "/data?time-series-code=wlp-hilo&from=" + \
          date_requise_debut + "T" + heure_requise_debut + "Z&to=" + \
          date_requise_fin + "T" + heure_requise_fin + "Z"

with urllib.request.urlopen(service_web+requete) as response:
    page_reponse = response.read()

# Récupération de la page de résultats au moyen de BeautifulSoup
dom_page_resultats = BeautifulSoup(page_reponse,"html.parser") 

# Conversion et affichage en format JSON
# essentiellement pour avoir un affichage pratique
json_page_resultats = json.loads(dom_page_resultats.get_text())
for element in json_page_resultats:
    print(element)<jupyter_output><empty_output><jupyter_text>Extraction des informations sur les maréesL'idée est de produire exactement le même fichier de données en .csv que celui obtenu par moissonnage du formulaire web. Voir le laboratoire précédent. Pour cela, il faut convertir l'heure données en temps universel (TU) en heure avancée de l'st (HAE).<jupyter_code>import datetime

def convertir_TU_HAE(entree_TU):
    # Extraction des paramètres pour la date et l'heure 
    # d'une chaîne de caractères du genre '2021-09-21T07:37:00Z'
    FORME2 = re.compile('(\d*)-(\d*)-(\d*)T(\d*):(\d*):(\d*)Z')
    formes_reconnues = re.search(FORME2,entree_TU)
    if formes_reconnues:
        annee = int(formes_reconnues.group(1))
        mois = int(formes_reconnues.group(2))
        jour = int(formes_reconnues.group(3))
        heure = int(formes_reconnues.group(4))
        minute = int(formes_reconnues.group(5))
        seconde = int(formes_reconnues.group(6))        
        date_et_heure = datetime.datetime(annee, mois, jour, heure, minute, seconde)
        # Conversion TU vers HAE par la soustraction de 4 heures
        temps_ajoute = datetime.timedelta(hours=4)
        nouveau_date_et_heure = date_et_heure - temps_ajoute
    # Retour d'une chaine de 
    return str(nouveau_date_et_heure)<jupyter_output><empty_output><jupyter_text>Extraction des informations sur les maréesOn extrait l'information utile sur les marées comme la date, l'heure convertie en HAE et la hauteur de la marée. Les autres informations comme `qcFlagCode` et `timeSeriesId` sont mises de côté.<jupyter_code>donnees_marees_liste = []

for evenement_maree in json_page_resultats:
    temps_HAE = convertir_TU_HAE(evenement_maree['eventDate'])
    hauteur_m = evenement_maree['value'] 
    donnees_marees_liste.append(temps_HAE.replace(' ','\t')+'\t'+str(hauteur_m))
print(donnees_marees_liste)<jupyter_output><empty_output><jupyter_text>Sauvegarde des données dans le fichier `donnees_marees_service_web.csv`Le fichier de données en format .csv est reconstitué à l'identique avec le fichier généré dans le laboratoire précédent.<jupyter_code># Sauvegarder les données dans un fichier .csv
chemin_fichier_sortie = './'
nom_fichier_sortie = "donnees_marees_service_web.csv"
municipalite_requise = 'Tadoussac'
fuseau_horaire_requis = 'HAE'

with open(chemin_fichier_sortie+nom_fichier_sortie,'w') as fichier_sortie:
    # Écriture de l'entête du fichier listant les différents attributs
    fichier_sortie.write('localite\tstation\tfuseau_horaire\tdate\theure\thauteur_m\n')
    for donnees_marees in donnees_marees_liste:
        # Écriture des données sur la marée dans le fichier
        fichier_sortie.write(municipalite_requise+'\t'+code_station+'\t'+fuseau_horaire_requis+'\t'+donnees_marees+'\n')
        
print("Données de marées sauvegardées dans le fichier "+ nom_fichier_sortie)<jupyter_output><empty_output><jupyter_text>Test de lecture du fichier de donnéesVérification que le fichier .csv est correct.<jupyter_code>import pandas as pd

donnees_marees_df = pd.read_csv(chemin_fichier_sortie+nom_fichier_sortie,delimiter='\t')
donnees_marees_df<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09984217958302184, 'fraction_numerical': 0.05058559681036631, 'mean_word_length': 5.666666666666667, 'pattern_counts': {'":': 61, '<': 33, '<?xml version=': 0, '>': 33, 'https://': 5, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '129408', 'license': 'Apache-2.0', 'n_tokens_mistral': 4620, 'n_tokens_neox': 4348, 'n_words': 1102, 'path': 'Labos/Lab-Traitement_Donnees/Interrogation_Services_Web.ipynb', 'repo_name': 'ClaudeCoulombe/VIARENA', 'size': '12039'}