= Importer des données tabulaires = De grandes quantités de données sont librement accessibles, notamment sur le site [[https://www.data.gouv.fr/fr/|data.gouv.fr]]. On peut les exploiter en classe. Pour importer ces données comme des tableaux, on dispose du module `csv` disponible dans la bibliothèque standard: tout tableur peut importer et exporter des données dans ce format. Prenons par exemple la liste intégrale des adresses des Bouches-du-Rhône, sous la forme d’un [[http://bano.openstreetmap.fr/BAN_odbl/BAN_odbl_13-csv.bz2|fichier CSV téléchargeable depuis le site d’OpenStreetMap]]. Ce fichier est compressé au format bzip2: il n’y a pas forcément de quoi ouvrir cette archive sur votre ordinateur… sauf que Python sait déjà gérer ce format, avec le module `bz2`. Jouons un peu: {{{#!highlight python import bz2 with bz2.open('BAN_odbl_13-csv.bz2') as f: for ligne in f.readlines(1000): # lit au plus 1000 octets print(ligne) }}} Bref, `bz2.open`, c’est comme `open`, sauf que ça décompresse à la volée. En regardant le contenu, on voit que : * le séparateur est la virgule `","`; * les entêtes des colonnes sont dans la première ligne. On est prêts à utiliser le module `csv` : on fabrique un objet itérable, sur lequel on peut faire une boucle `for`. {{{#!highlight python import csv with bz2.open('BAN_odbl_13-csv.bz2') as f: lecteur = csv.reader(f) for ligne in lecteur: print(ligne) }}} Ça râle, parce que par défaut, un fichier `bz2` est lu en mode binaire (on obtient des séquences d’octets) alors que le module `csv` veut du texte (des chaînes de caractéres). Comme dit dans la documentation de `bz2`, il faut ajouter l’argument 'rt': {{{#!highlight python import csv with bz2.open('BAN_odbl_13-csv.bz2','rt') as f: lecteur = csv.reader(f) for ligne in lecteur: print(ligne) }}} C’est long ! Si on veut seulement lire ligne à ligne, on peut utiliser la primitive `next` qui renvoie la première entrée d’un itérateur, et passe à la suivante. {{{#!highlight python import csv with bz2.open('BAN_odbl_13-csv.bz2','rt') as f: lecteur = csv.reader(f) for i in range(10): print(next(lecteur)) }}} Mais ça représente un volume de données raisonnable pour un ordinateur d’aujourd’hui : on peut tout charger en mémoire pour le traiter. Avec tout ce qu’on a vu jusque là, on obtient le début programme : {{{#!highlight python def lit_csv(f): """Lit un objet fichier `f` au format CSV, et retourne le couple `(entête,lignes)`: * `entête` est la première ligne ; * `lignes` est le tuple des lignes suivantes. """ import csv lecteur = csv.reader(f) entête = next(lecteur) lignes = tuple(lecteur) return entête, lignes def ligne_avec_entête(entête,ligne): "Renvoie une chaîne qui représente les valeurs de la `ligne`." entrées = [] for i in range(len(entête)): entrée = entête[i] + ": " + ligne[i] entrées = entrées + [entrée] return " | ".join(entrées) if __name__ == '__main__': import bz2 with bz2.open('BAN_odbl_13-csv.bz2','rt') as f: entête, lignes = lit_csv(f) print("Les colonnes du fichier sont :", ", ".join(entête)) print("Il y a",len(lignes),"entrées") print("Première ligne :") print(ligne_avec_entête(entête,lignes[0])) print("Dernière ligne :") print(ligne_avec_entête(entête,lignes[-1])) }}} À vous de jouer. Par exemple, définissez une fonction qui renvoie la liste de tous les numéros d’une rue donnée dans une ville donnée. Ou la liste de toutes les rues d’une ville donnée.