Outils pour utilisateurs

Outils du site


issue146:python

Many regular readers of this column might have wondered why I haven't dealt with JSON files in any of my articles to date. Well, that's a good question. Partially, the reason that I haven't is that it didn't really fit into any of the subjects that I was trying to explain. Now, however, I will open the topic so we can explore it.

Beaucoup de lecteurs réguliers de cette rubrique ont pu s'étonner que je ne me sois jamais préoccupé des fichiers JSON dans aucun de mes articles jusqu'à maintenant. C'est une bonne question.

En partie, la raison pour laquelle je ne l'ai pas fait est que ça ne collait pas vraiment avec les sujets que j'essayais d'expliquer. Cependant, j'ouvre maintenant le sujet ; ainsi, nous pouvons l'explorer.

So, what exactly is JSON? JSON stands for JavaScript Object Notation. It's a way to read, write and exchange data using an industry standard. Python has a library that deals with JSON data. Here (top right) is a short sample of some JSON data (I borrowed this example from https://developer.rhino3d.com/guides/rhinopython/python-xml-json/) Does this look somewhat familiar? It obviously has a key:value structure to it. Something like a dictionary in Python? Hmmmmm.

Alors, qu'est-ce que JSON exactement ?

JSON veut dire JavaScript Object Notation. C'est une façon de lire, d'écrire et d'échanger des données en utilisant une norme de l'industrie. Python a une bibliothèque qui traite les données JSON.

En haut à droite, voici un court échantillon de données JSON (J'ai emprunté cet exemple sur https://developer.rhino3d.com/guides/rhinopython/python-xml-json/)

Cela ne vous paraît-il pas familier ? Il a d'évidence une structure clé:valeur. Quelque chose comme un dictionnaire dans Python ? Hmmmm.

I was going to give you an example of getting and working with some JSON data by using Weather Underground, but they have removed the free access. So, I've decided to try the Dark SKY API. In order to use their service, you need to sign up for a free account. This account will give you up to 1000 free API requests per day. This should be enough for you to do some testing on your own. When I was trying out the code for this month, I used way less than 40 requests. You can sign up at https://darksky.net/dev/docs and click on the “SIGN UP” button in the upper-right corner of the page. They will send you an email requesting you to confirm your email address with a link. Once you do that, they will provide you with your own secret key. Now, one of the requirements of the service is that you keep your secret key, well, secret, so I won't disclose my key. I'll use “{secretkey}” wherever it's required. What I'll do to make it easy is to create a variable and assign the value to it. That way, you can use your secret key by simply plugging it into the code I will provide.

J'allais vous donner un exemple de l'acquisition et du travail avec des données JSON en utilisant « Weather Underground », mais ils ont supprimé l'accès libre. Aussi, j'ai décidé d'essayer l'API Dark SKY. Pour utiliser leurs services, vous devez vous inscrire à un compte gratuit. Ce compte vous permet d'exécuter jusqu'à 1 000 demandes gratuites d'API par jour. Ça devrait vous suffire pour faire quelques tests par vous-même. Quand j'ai testé le code de ce mois, j'ai utilisé largement moins de 40 demandes. Vous pouvez vous inscrire sur https://darksky.net/dev/docs en cliquant sur le bouton « SIGN UP » (inscription) dans le coin en haut à droite de la page. Ils vous enverront un mail pour confirmer votre adresse mail avec un lien. Une fois fait, ils vous fourniront votre clé secrète personnelle.

L'un des desiderata du service est que vous gardiez votre clé secrète, disons… secrète ; aussi, je ne vous dévoile pas ma clé. J'utiliserai « {secretkey} » (clésecrète) quand c'est nécessaire. Pour simplifier, je créerai une variable et je lui assignerai la valeur. De cette façon, vous pouvez utiliser votre clé secrète en la glissant dans le code que je fournirai.

Let's try it out. In addition to the API Key, you'll need to know the Latitude and Longitude of the area you are interested in. If you don't know your latitude and longitude off the top of your head, you can got to https://www.latlong.net/ and enter your city and country. I'll use that lat and lon for Austin, Texas… latlon = 30.2672° N, -97.7431° W So, our call will be… https://api.darksky.net/forecast/{secretkey}/30.2672,-97.7431 (The additional calls can get somewhat complex, so we'll start with the full report). We'll start out by testing it in a browser. Put the above address into the browser address box. What you'll get back is quite a bit of data. If you are using Google Chrome, be sure to either add or enable JSONview extension. Firefox shows the JSON pretty print by default.

Essayons-la. En plus de votre Clé d'API, vous devrez connaître les longitude et latitude de l'endroit qui vous intéresse. Si vous ne connaissez pas les longitude et latitude à brûle-pourpoint, vous pouvez aller sur https://www.latlong.net/ et saisissez votre ville et votre pays. J'utiliserai les coordonnées d'Austin, au Texas.

latlon = 30.2672° N, -97.7431° W

Ainsi, notre appel sera…

https://api.darksky.net/forecast/{secretkey}/30.2672,-97.7431

(Les appels complémentaires peuvent être quelque peu complexes ; aussi, nous commençons par un rapport complet.)

Nous commencerons par le tester dans notre navigateur. Mettez l'adresse ci-dessus dans le champ d'adresse du navigateur. Ce qui vous sera renvoyé est une quantité de données appréciable. Si vous utilisez Google Chrome, assurez-vous d'ajouter ou d'autoriser l'extension JSONview. Par défaut, Firefox affiche bien le JSON.

Here (next page, top right) is an abbreviated version of the output data, I purposely have edited it so that it contains only the header and the 'currently' section. Even though I limited it to the header and ‘currently’ sections, that’s a lot of data. Some of it might be important to you and some might not be so important. Before going any further, please save a copy of the data. For Chrome, right-click in the window and select “Save as..”. In Firefox, you can simply click the save button. Then save the file as “sampledata.json” somewhere easy to get to. This way, we can use it instead of a “live” feed while we are developing our program without costing “live” calls. Remember, 1000 calls per day sounds like a bunch, but during learning and development, it can go quickly.

Voici (page suivante, en haut à droite) une version abrégée des données de sortie ; je l'ai délibérément modifiée pour qu'elle ne contienne que l'entête et la section « currently ».

Bien que je l'aie limitée à l'entête et la section « currently », ça fait beaucoup de données. Certaines d'entre elles peuvent avoir une importance pour vous et d'autres moins.

Avant d'aller plus loin, merci de sauvegarder une copie des données. Pour Chrome, faites un clic droit dans la fenêtre et sélectionnez « Enregistrer sous ». Dans Firefox, vous n'avez qu'à appuyer sur le bouton Enregistrer. Puis, sauvegardez le fichier comme « sampledata.json » dans un endroit facile d'accès. De cette façon, nous pouvons l'utiliser à la place d'une connexion directe pendant que nous développons notre programme sans que ça nous coûte des appels directs. Souvenez-vous que 1 000 appels par jour semble un gros paquet, mais, pendant l'apprentissage et le développement, ça peut aller très vite.

Now we can look at the information presented. We have some header information, then a series of sections called “currently”, “minutely”, “hourly”, “daily”, “flags” and there might be one called “alerts”. When you make a “full” call as we did above, you get everything. You can use the “exclude” option to filter out the items you don't want or need to see (more on that in a bit). However, right now, let's just concentrate on the “currently” section. As you can see, there is a time field that is a UNIX timestamp, fields for summary, storm information (if there is a storm around), temperature, dewpoint, humidity, pressure, wind, and much more. For the most part, these same data are available in the “daily” and “hourly” sections as well. Some of the fields may not be available when you call for data. Mainly things like the storm information are – only if there is a storm nearby. Now let's start talking Python code. Create a new python file called ‘DarkskyJSON.py’ and put it in the same folder that you put the sample data download earlier.

Maintenant, nous pouvons regarder l'information présentée. Nous avons quelques informations d'entête, puis une série de sections appelées « currently », « minutely », « hourly », « daily », « flags » et il peut y en avoir une appelée « alerts ». Quand on fait un appel « complet » comme celui du dessus, on obtient tout. Vous pouvez utiliser l'option « exclude » pour éliminer les sujets que vous ne voulez ou n'avez pas besoin de voir (plus là-dessus sous peu). Cependant, pour le moment, concentrons-nous sur la section « currently ».

Comme vous pouvez le voir, il y a un champ « time » qui est l'horodatage UNIX, des champs pour une synthèse (summary), des informations sur les orages (storm - s'il y a un orage dans le voisinage), la température, le point de rosée (dewpoint), l'humidité, la pression, le vent et encore plus. Pour la plupart, ces données sont les mêmes que celles des sections « hourly » et « daily ». Certains champs pourraient ne pas être disponibles quand vous demandez des données. C'est le cas surtout pour des informations comme les orages, présentes seulement en cas d'orage dans le voisinage.

Maintenant, commençons à parler du code en Python. Créez un nouveau fichier Python appelé « DarkskyJSON.py » et placez-le dans le même dossier que les données échantillon téléchargées précédemment.

Let’s start with the import section: import json import requests from datetime import datetime You might be thinking that it makes sense to import the json library, but why requests and datetime libraries? The json library is obvious. The requests library is so we can make a http request directly from our program. And datetime is so we can convert the unix timestamp to a value that normal humans can understand at a glance. By the way, you might want to do a “pip3 list” in a terminal to see if requests is already installed. Ok. Moving on. The first task is to work with the local file (below), so we’ll write some code to load that JSON data. I made a copy of my local file – to keep it safe – and named it ‘sampledata.json’.

Commençons par la section import :

import json

import requests

from datetime import datetime

Vous devez penser que ça a du sens d'importer la bibliothèque json, mais pourquoi les bibliothèques requests et datetime ? C'est évident pour la bibliothèque json. La bibliothèque requests est ainsi faite que nous pouvons faire une requête http directement depuis notre programme. Et datetime est telle que nous pouvons convertir l'horodatage unix en une valeur que des humains normaux peuvent comprendre d'un coup d'œil. Pendant qu'on y est, vous pourriez vouloir faire un « pip3 list » dans un terminal et voir si requests est déjà installé.

Bon. Avançons. La première tâche est de travailler avec notre fichier local (ci-dessous) ; aussi, nous écrirons un peu de code pour charger ces données JSON. J'ai fait une copie de mon fichier local - pour le conserver - et je l'ai appelé « sampledata.json ».

This should mainly look familiar to you. We’ve done it many times over the years. The only difference is that we are telling the JSON library to load the file and return it as a Python dictionary called ‘response’. When we print it to the terminal, it should look something like this… {'latitude': 30.2672, 'longitude': -97.7431, 'timezone': 'America/Chicago', # 'currently': {'time': 1558447441, 'summary': 'Light Rain', 'icon': 'rain', 'nearestStormDistance': 0, 'precipIntensity': 0.0206, 'precipIntensityError': 0.0203, 'precipProbability': 0.73, 'precipType': 'rain', 'temperature': 79.43, 'apparentTemperature': 82.99, 'dewPoint': 72.49, 'humidity': 0.79, 'pressure': 1004.58, 'windSpeed': 6.51, 'windGust': 12.42, 'windBearing': 275, 'cloudCover': 0.72, 'uvIndex': 2, 'visibility': 6.7, 'ozone': 299.33}, 'offset': -5} Again, things like ‘nearestStormDistance’ and ‘‘precipType’ might not be available when you make your requests. We’ll deal with those in a few moments.

Ceci devrait vous paraître assez habituel. Nous l'avons fait de nombreuses fois pendant toutes ces années. La seule différence est que nous disons à la bibliothèque JSON de charger le fichier et de le retourner comme un dictionnaire Python appelé « response » (réponse). Quand nous l'imprimons dans le terminal, il doit ressembler à ceci :

{'latitude': 30.2672, 'longitude': -97.7431, 'timezone': 'America/Chicago',

# 'currently': {'time': 1558447441, 'summary': 'Light Rain', 'icon': 'rain', 'nearestStormDistance': 0, 'precipIntensity': 0.0206, 'precipIntensityError': 0.0203, 'precipProbability': 0.73, 'precipType': 'rain', 'temperature': 79.43, 'apparentTemperature': 82.99, 'dewPoint': 72.49, 'humidity': 0.79, 'pressure': 1004.58, 'windSpeed': 6.51, 'windGust': 12.42, 'windBearing': 275, 'cloudCover': 0.72, 'uvIndex': 2, 'visibility': 6.7, 'ozone': 299.33}, 'offset': -5}

Une fois encore, pensez que des choses comme « nearestStormDistance » et « precipType » pourraient être absentes quand nous faisons des requêtes. Nous traiterons celles-ci dans un petit moment.

Now, we’ll deal with the current time. That shows up in the ‘currently’ section as ‘time’. Since I live in the U.S., I’ll use a datetime format that makes it easy for me. I’m sure you know by now how to do it for yourself. But just in case, here’s a quick memory aid reminder link: https://www.programiz.com/python-programming/datetime/strftime tim = response['currently']['time'] print(datetime.fromtimestamp(tim).strftime(“%a %m/%d/%Y %H:%M:%S”)) Assuming that the value for ‘time’ is 1558447441, the output would be: Thu 05/23/2019 19:30:20 And that makes perfect sense to me. Now, to help break down the first line of the above code, ‘response’ is the full data packet we got from the JSON library read, ‘currently’ is the section we want to deal with, and ‘time’ is the key that we want. It’s just that simple.

Maintenant, occupons-nous du temps présent. Il se présente sous « time » dans la section « currently ». Comme je vis aux USA, j'utiliserai le format temporel qui m'est facile. Je suis sûr que vous savez maintenant comment l'adapter pour vous. Mais, juste au cas où, voici un lien pour un rapide aide-mémoire : https://www.programiz.com/python-programming/datetime/strftime

tim = response['currently']['time']

print(datetime.fromtimestamp(tim).strftime(“%a %m/%d/%Y %H:%M:%S”))

Si la valeur de « time » est 1558447441, la sortie devrait être :

Thu 05/23/2019 19:30:20

Et, pour moi, c'est compréhensible. Maintenant, pour nous aider à décomposer la première ligne du code ci-dessus, « response » est le paquet de données complet que nous avons obtenu par la lecture de la bibliothèque JSON, « currently » est la section que nous voulons traiter et « time » est la clé que nous voulons. Rien de plus simple.

Now, we can play some simplifying games with the data so we don’t have to type so much. For example… currents = response['currently'] summary = currents['summary'] If we print the summary variable, we will get: 'Light Rain' Again, to carry on with the key:value dictionary analogy, ‘currents’ is the section of the data, ‘summary’ is the key and ‘Light Rain’ is the value. We also assigned (in the first line of the two) the entire ‘currently’ section of the returned data dictionary to a dictionary named currents. So now, when we want any value within the currents dictionary, we just put the key for that value in square brackets. Here (top) are a few more examples set as print statements.

Maintenant, nous pouvons jouer à simplifier un peu les données pour en avoir moins à saisir. Par exemple :

currents = response['currently'] summary = currents['summary']

Si nous imprimons la variable summary, nous obtiendrons :

'Light Rain'

À nouveau, pour faire l'analogie avec le dictionnaire clé:valeur, « currents » est la section des données, « summary » est la clé et 'Light Rain' est la valeur. Nous avons assigné aussi (dans la première des deux lignes) la section complète « currently » du dictionnaire de données à un dictionnaire nommé currents. Aussi, maintenant, quand nous voulons n'importe quelle valeur dans le dictionnaire currents, nous avons juste à mettre la clé de cette valeur entre crochets. Ci-dessus, vous voyez quelques autres exemples placés dans des déclarations print.

And our output would look, using the above response data, something like this: Temperature: 84.43 Feels like: 90.54 Dew point: 72.43 Humidity: 67.0% It’s not as bad as it seemed when we started this article, now was it? Now, how to handle a field so that: • if it is available, show it, • if not, don’t encounter an error? We’ll use the precipType key as an example. If it’s raining or snowing, it will be available, but if it’s sunny, it won’t be in the data structure. Here’s how: if 'precipType' in response['currently']: print(“ Precip Type: {0}”.format(response['currently']['precipType']))

Et notre sortie ressemblera, en utilisant les données de réponse ci-dessus, à quelque chose comme :

 Temperature: 84.43
 Feels like: 90.54
 Dew point: 72.43
 Humidity: 67.0%

Ça n'est pas aussi difficile qu'il y paraissait au début de cet article, n'est-ce-pas ? Maintenant, comment manipuler un champ de sorte que : ••s'il est disponible, il est présenté, ••s'il ne l'est pas, qu'il n'y ait pas d'erreur ?

Nous utiliserons la clé precipType comme exemple. S'il pleut ou neige, elle sera disponible, mais si le soleil brille, elle ne sera pas présente dans les données. Voici comment :

if 'precipType' in response['currently']:

 
 print("   Precip Type: {0}".format(response['currently']['precipType']))

So, if the data structure response[‘currently’] has a key of ‘precipType’, we’ll print it, otherwise we’ll just go on without any problems. That’s the ‘key in dictionary’ part of the if clause. Again, to many of you, we’ve done this kind of thing before so it’s old hat. To others, this is new information. Now we’ll look at the way to get the live data. We start with defining a number of variables so we can just “plug and play” into a string. Here’s the code (top right). Note that the requests call takes no consideration of timeout settings. This is easy to change, if it is a concern to you. Simply add one line and replace the last two lines of the above code: timeout = 10 # 10 second timeout session = requests.Session() response = session.get(url, timeout=timeout).json()

Aussi, si dans la structure de données de réponse[‘currently’] la clé « precipType » est présente, nous l'imprimerons ; autrement, nous continuerons sans problème. C'est la partie « clé dans le dictionnaire » de la clause if. À nouveau, pour beaucoup d'entre vous, nous avons déjà fait de telles choses ; c'est donc un vieux sujet. Pour les autres ce sont des informations nouvelles.

Maintenant, regardons, la manière d'obtenir les données en direct. Nous commençons par définir un certain nombre de variables de sorte que nous pouvons les avoir simplement prêtes à l'emploi dans une chaîne. Voici le code (en haut à droite).

Notez que l'appel de requests ne prend pas en compte les réglages de délai dépassé. C'est facile à changer, si ça vous pose problème. Ajoutez simplement une ligne et remplacez les deux dernières lignes du code ci-dessus :

timeout = 10 # limite de temps de 10 secondes

session = requests.Session()

response = session.get(url, timeout=timeout).json()

Now we have the JSON data structure in our dictionary, just like we read it from the local file earlier. So now, you can comment our four lines that read the local file, and add the lines above. This way, if you want to play some more, you can still work with the local file by commenting out the “live” request code and uncommenting the local file-read code. I’ve got a fully functioning demonstration program that I’ve created (without my secret key of course, but you can put yours in) and I’ve put it up on pastebin. The address is https://pastebin.com/yJ7dJGis . For those of you who don’t live in the US, and/or don’t use English as your primary language, there are various options for you that keep you from having to write Fahrenheit to Celsius conversion functions, and will present the display text in a language that you want. For example, if you want to see the output in Norwegian, you can pass “nb” within the URL as language and “si” as the units. Below is a modified URL string creation statement that you can use to set things up correctly. Set ‘unitstouse’ as “si” and ‘langtouse’ to ‘nb’. If you want Spanish, use “es”. If you want German, use “de”, and so on. It’s all in the API docs.

Maintenant nous avons la structure de données en JSON dans notre dictionnaire, exactement comme nous les lisions précédemment à partir du ficher. Aussi, nous pouvons commenter nos quatre lignes qui lisent le fichier local et ajouter les lignes ci-dessus. De cette façon, si vous voulez continuer à tester, vous pouvez encore utiliser le fichier local en commentant le code de demande directe et en décommentant le code de lecture du fichier local.

J'ai pris le programme de démonstration complètement fonctionnel que j'avais créé (sans ma clé secrète, bien sûr, mais vous pouvez mettre la vôtre) et je l'ai porté sur pastebin. L'adresse est https://pastebin.com/yJ7dJGis.

Pour ceux qui ne vivent pas aux USA, et/ou dont l'anglais n'est pas la langue maternelle, vous disposez de nombreuses options qui vous évitent de devoir écrire des fonctions de conversion des Fahrenheit en Celsius et qui présenteront le texte affiché dans la langue que vous voulez. Par exemple, si vous voulez que la sortie soit en norvégien, vous pouvez passer dans l'URL « nb » comme langue et « si » comme unités. Ci-dessous, vous trouvez une déclaration de création d'une chaîne d'URL modifiée que vous pouvez utiliser pour régler les choses correctement. Changez « unitstouse » en « si » et « langtouse » en « nb ». Si vous voulez de l'espagnol, utilisez « es ». Pour l'allemand, « de » et ainsi de suite. Tout est dans les docs d'API.

Where to go from here? Well, if you go back to the DarkSky API Documentation page I directed you to before, they have a full list of all the keys that are available. They include daily forecasts for the current day plus seven days, hourly forecasts, changing the output language and units of measurements, minute by minute forecasts for the next hour, alerts for severe weather information, and even a “time machine mode” that allows you to include a date in the past or in the future and get the observed (past) or forecasted (future) data. I haven’t played with these two options yet, so I don’t know how far backwards or forwards you can go. If you are a “weather geek” like me, this can be a very fun project. It would be pretty easy to put this code into a GUI. We might do that sometime in the future. Start up the Time Machine!

Où aller à partir de là ? Eh bien, si vous retournez à la page de documentation de l'API DarSky vers laquelle je vous ait dirigé précédemment, vous trouverez une liste complète de toutes les clés disponibles. Elles comprennent les prévisions quotidiennes pour aujourd'hui et les sept jours suivants, des prévisions à l'heure, la possibilité de changer la langue de sortie et les unités de mesure, des prévisions minute par minute pour la prochaine heure, des alertes d'informations sur du mauvais temps, et même un « time machine mode » (mode « machine à remonter le temps ») qui vous permet d'inclure une date dans le passé ou le futur pour disposer des données observées (passé) ou prévues (futur). Je n'ai pas encore joué avec ces options ; aussi, je ne sais pas de combien vous pouvez vous éloigner du temps présent dans un sens ou dans l'autre.

Si vous êtes un « fana de météo » comme moi, ceci peut être un très amusant projet. Il devrait être assez facile de mettre ce code dans une interface graphique. Nous pourrions faire cela à un moment quelconque dans le futur.

Démarrez la machine à remonter le temps !

issue146/python.txt · Dernière modification: 2019/07/16 23:06 par andre_domenech