
Salut la foule. Ca fait un bail… Me revoilà sur Home Assistant, et je cherche des solutions à différents problèmes.
L’un d’eux est que l’intégration Meteo Suisse ne fonctionne pas. J’ai donc commencé à creuser pour savoir si je pourrais résoudre le problème.
La base publique suisse opendata.swiss met à disposition le fichier des données à 10 minutes pour la météo en Suisse. Toutefois, le fichier ne contient pas directement les données. Il s’agit d’un fichier ZIP qui contient un fichier TXT qui lui contient le lien vers le fichier CSV. Pourquoi faire simple quand on peut faire compliqué.
Je partage donc ici mes trouvailles au cas où ça pourrait servir à quelqu’un.
En résumé, j’ai besoin de:
- Télécharger un fichier ZIP
- En extraire le fichier texte qui contient l’URL vers le fichier CSV
- Récupérer le lien vers le fichier CSV
On commence par importer les modules qui nous seront utiles:
from io import BytesIO
from zipfile import ZipFile
import requests
import re
import sys
- ByteIO permet d’ouvrir un fichier binaire en mémoire. Ca permet de ne pas écrire le fichier sur le disque
- zipfile a un nom assez parlant. Il permet de gérer … Ouiiii bravoooo, les fichiers ZIP
- requests va nous permettre de faire une requête pour télécharger le fichier
- re permettra de rechercher les info qui correspondent à l’expression régulière proposée (ici, une URL)
- and sys me sert à quitter le script en spécifiant un code d’erreur. Même si ici, il n’y a pas grand chose à spécifier. Mais on peut si on veut…
Ensuite, on définit les variables nécessaires à ce script.
- url contiendra le lien vers le fichier ZIP. On suppose que ce lien est connu
- filestr contiendra un mot clé permettant d’identifier le fichier texte à extraire, considérant bien sûr qu’on en connaît au moins une partie. Ici, le nom du fichier à extraire contient les lettres URL
- urlstr permettra de localisé l’URL contenant la clé que l’on recherche. Dans mon cas, la clé est csv puisque je recherche un lien vers un fichier CSV
- regularex est une expression régulière (trouvée sur le net) qui permettra d’extraire les URL du fichier texte
url = "https://whateverurlyouneed"
# Define string to be found in the file name to be extracted
filestr = "anystring"
# Define string to be found in URL to parse
urlstr = "anyotherstring"
# Define regex to extract URL
regularex = r"(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|(([^\s()<>]+|(([^\s()<>]+)))))+(?:(([^\s()<>]+|(([^\s()<>]+))))|[^\s`!()[]{};:'\".,<>?«»“”‘’]))"
La prochaine étape consiste à télécharger le fichier ZIP et l’enregistrer dans une variable “content”:
content = requests.get(url)
Puis charger le fichier ZIP en mémoire:
zipfile = ZipFile(BytesIO(content.content))
De là, on va extraire le fichier texte dont le nom contient la clé contenue dans la variable filestr, souvenez-vous dans mon cas, “URL”. Nous allons ouvrir ce fichier et inscrire son contenu dans une variable appelée “data”:
data = [zipfile.open(file_name) for file_name in zipfile.namelist() if filestr in file_name][0]
Enfin, nous allons lire chaque ligne de cette variable, et en extraire les URL contenant la clé “csv”. Puis nous arrêterons la boucle à la première occurrence.
for line in (line for line in data.readlines() if urlstr in line.decode("latin-1")):
urls = re.findall(regularex,line.decode("latin-1"))
print([url[0] for url in urls])
break
On finit par sortir du script avec un code d’erreur 0.
sys.exit(0)
Voici donc le script complet:
#!/bin/env python
from io import BytesIO
from zipfile import ZipFile
import requests
import re
import sys
# define url value
url = "https://whateverurlyouneed"
# Define string to be found in the file name to be extracted
filestr = "anystring"
# Define string to be found in URL
urlstr = "anyotherstring"
# Define regex to extract URL
regularex = r"(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|(([^\s()<>]+|(([^\s()<>]+)))))+(?:(([^\s()<>]+|(([^\s()<>]+))))|[^\s`!()[]{};:'\".,<>?«»“”‘’]))"
# download zip file
content = requests.get(url)
# Open stream
zipfile = ZipFile(BytesIO(content.content))
# Open first file from the ZIP archive containing
# the filestr string in the name
data = [zipfile.open(file_name) for file_name in zipfile.namelist() if filestr in file_name][0]
# read lines from the file. If csv found, print URL and exit
# This will return the 1st URL containing CSV in the opened file
for line in (line for line in data.readlines() if urlstr in line.decode("latin-1")):
urls = re.findall(regularex,line.decode("latin-1"))
print([url[0] for url in urls])
break
sys.exit(0)