2022-10-03
J’ai eu envie de faire un rapport sur la météo et ça tombe bien, Météo France donne accès à l’historique d’une cinquantaine de stations sur 15 ans. On peut télécharger les données ici pour une date ou pour un mois précis.
]
Je rencontre deux problématiques :
En téléchargeant un premier fichier j’identifie le format du nom du fichier : l’année et le mois sont indiqués dans l’adresse.
donneespubliques.meteofrance.fr/donnees_libres/Txt/Synop/Archive/synop.202210.csv.gz
Il suffit de changer l’année et le mois pour accéder aux données d’une autre période. Avec un langage procédural ce serai facile de récupérer tout l’historique dans une boucle :
$i = 0
while($i -lt 12){
$m = ((Get-Date).AddMonths(-1 * $i)) | Get-Date -Format "yyyyMM"
$uri = "https://donneespubliques.meteofrance.fr/donnees_libres/Txt/Synop/Archive/synop." + $m + ".csv.gz"
Invoke-RestMethod $uri -Method 'GET' -OutFile $("synop." + $m + ".csv.gz")
$i = $i + 1
}
Mais dans PowerQuery, il n’y a pas de boucle. Il faut donc procéder en 3 étapes :
Disons que l’on veuille récupérer 3 ans d’historique, soit 36 mois :
= List.Generate(() > 0, each _ <= 36, each _ + 1)
= Table.AddColumn(#"Colonnes renommées", "Code Mois", each DateTime.ToText(Date.AddMonths(Date.EndOfMonth(DateTime.LocalNow()), 0 - [Offset]), "yyyyMM"))
Web.Contents
. Il est indispensable d’utiliser l’instruction en précisant le nom du site comme premier paramètre et le chemin du fichier comme option RelativePath
. Si on ne fait pas ça (et si on met une url complète comme unique paramètre), la requête est considérée comme dynamique et ne peut pas être actualisée par le service powerbi.com.= Table.AddColumn(#"Chemin Fichier ajouté", "Fichier", each Web.Contents("https://donneespubliques.meteofrance.fr", [RelativePath = [Chemin Fichier]]))
Les fichiers récupérés sont des CSV compressés en ZIP.
Il faut les décompresser pour ensuite les traiter. Pour cela on utilise l’instruction Binary.Decompress
(je pense que le nom est assez explicite).
Une fois le fichier lisible, on le traite comme un CSV et on remonte la première ligne en en-tête.
Tout ce processus doit être encapsulé dans une fonction pour pouvoir être appelé pour chaque ligne de notre première requête :
(ZIPFile) =>
let
Source = Binary.Decompress(ZIPFile, Compression.GZip),
Read = Csv.Document(Source, [Delimiter=";", Encoding=1252, QuoteStyle=QuoteStyle.None]),
Header = Table.PromoteHeaders(Read, [PromoteAllScalars=true])
in
Header
On appelle la fonction Unzip histoire de rester original.
On a la liste des fichiers (téléchargés en binaire) et une fonction pour les lire, il ne reste plus qu’à utiliser tout ça.
Dans la première requête, on crée une nouvelle colonne en appelant une fonction personnalisée : la fonction Unzip crée précédemment ! La fonction prend en paramètre la colonne des fichiers en binaire.
On peut à présent développer la nouvelle colonne pour récupérer le contenu de chaque fichier dans la même table.
Le script complet de la requête PowerQuery est :
let
Source = List.Generate(() > 0, each _ <= 36, each _ + 1),
#"Converti en table" = Table.FromList(Source, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#"Colonnes renommées" = Table.RenameColumns(#"Converti en table",Column1),
#"Code Mois ajouté" = Table.AddColumn(#"Colonnes renommées", "Code Mois", each DateTime.ToText(Date.AddMonths(Date.EndOfMonth(DateTime.LocalNow()), 0 - [Offset]), "yyyyMM")),
#"Chemin Fichier ajouté" = Table.AddColumn(#"Code Mois ajouté", "Chemin Fichier", each "donnees_libres/Txt/Synop/Archive/synop." & [Code Mois] &".csv.gz"),
#"Fichier ajouté" = Table.AddColumn(#"Chemin Fichier ajouté", "Fichier", each Web.Contents("https://donneespubliques.meteofrance.fr", [RelativePath = [Chemin Fichier]])),
#"Fonction personnalisée appelée" = Table.AddColumn(#"Fichier ajouté", "Unzip", each Unzip([Fichier])),
#"Autres colonnes supprimées" = Table.SelectColumns(#"Fonction personnalisée appelée",{"Unzip"}),
#"Unzip développé" = Table.ExpandTableColumn(#"Autres colonnes supprimées", "Unzip", {"numer_sta", "date", "pmer", "tend", "cod_tend", "dd", "ff", "t", "td", "u", "vv", "ww", "w1", "w2", "n", "nbas", "hbas", "cl", "cm", "ch", "pres", "niv_bar", "geop", "tend24", "tn12", "tn24", "tx12", "tx24", "tminsol", "sw", "tw", "raf10", "rafper", "per", "etat_sol", "ht_neige", "ssfrai", "perssfrai", "rr1", "rr3", "rr6", "rr12", "rr24", "phenspe1", "phenspe2", "phenspe3", "phenspe4", "nnuage1", "ctype1", "hnuage1", "nnuage2", "ctype2", "hnuage2", "nnuage3", "ctype3", "hnuage3", "nnuage4", "ctype4", "hnuage4", ""}, {"numer_sta", "date", "pmer", "tend", "cod_tend", "dd", "ff", "t", "td", "u", "vv", "ww", "w1", "w2", "n", "nbas", "hbas", "cl", "cm", "ch", "pres", "niv_bar", "geop", "tend24", "tn12", "tn24", "tx12", "tx24", "tminsol", "sw", "tw", "raf10", "rafper", "per", "etat_sol", "ht_neige", "ssfrai", "perssfrai", "rr1", "rr3", "rr6", "rr12", "rr24", "phenspe1", "phenspe2", "phenspe3", "phenspe4", "nnuage1", "ctype1", "hnuage1", "nnuage2", "ctype2", "hnuage2", "nnuage3", "ctype3", "hnuage3", "nnuage4", "ctype4", "hnuage4", "Colonne1"})
in
#"Unzip développé"
Si on souhaite améliorer la requête et se conformer aux bonnes pratiques :
= Table.AddColumn(#"Personnalisée ajoutée", "Fichier", each Web.Contents(#"Base Uri", [RelativePath = Text.Replace(#"Complement Uri", "<mois>", [Code Mois])]))