Inovia Blog

L’actualité des technologies innovantes

Sécuriser une API REST avec JSON Web Token (JWT)

Par Kadda SAHNINE

Publié le | 26 novembre 2015 | Pas de commentaire

JWT


Mon article consacré la spécification CORS a eu un certain succès d’audience. Il me semble opportun de le compléter avec un nouvel article traitant de la sécurisation d’une API REST.
J’ai choisi d’aborder JSON Web Token (JWT, que les anglophones prononcent jot), un standard ouvert permettant à deux parties d’échanger de manière sûre des informations encapsulées dans un jeton signé numériquement.
En pratique, JWT est utilisé pour mettre en oeuvre des solutions d’authentification SSO ou de sécurisation de web services.

Bien que le protocole OAuth 2 soit très utilisé par des plateformes à forte audience exposant une API web, JWT apparait dans beaucoup de cas d’utilisation comme une alternative intéressante car beaucoup plus simple à mettre en oeuvre et stateless (ce qui rend la solution scalable).

Après avoir décrit la structure et l’utilisation d’un “jot“, nous verrons en pratique comment sécuriser une API REST construite sur Node.js et le service de gestion d’identité Stormpath. Le code source accompagnant cet article est disponible sur mon dépôt GitHub.

Structure d’un jeton JWT

Un jeton JWT est une chaîne de caractères décomposable en 3 sections séparées par un point (.).

Jeton JWT

  • En-tête : c’est un document au format JSON, encodé en base 64 et contenant des méta-données. Il doit contenir au minimum le type de jeton et l’algorithme de chiffrement utilisé pour le signer numériquement.
    Exemple :

    {
      "typ": "JWT",
      "alg": "HS256"
    }
    
  • Charge utile : cette section est un document au format JSON encodé en base 64, contenant des données fonctionnelles minimales que l’on souhaite transmettre au service (ces propriétés sont appelées claims ou revendications selon la terminologie de la RFC). En pratique, on y fait transiter des informations sur l’identité de l’utilisateur (login, nom complet, rôles, etc.). Il ne doit pas contenir de données sensibles. Voici un exemple :
    {
      "iat": 1448383708,
      "exp": 1448383768,
      "name": "compte de test",
      "username": "demo",
      "email": "demo@foobar.com"
    }
    

    A noter que l’on distingue 3 types de claims :

    • claims réservés : il s’agit de noms réservés par la spécification et ne pouvant être utilisés par le développeur. Par exemple, iat contient la date de génération du jeton et exp sa date d’expiration.
    • claims publics : il s’agit de noms normalisés dont on encourage l’utilisation (ex. name, email, phone_number). Le registre est maintenu par l’organisation IANA et est consultable sur leur site.
    • claims privés : il s’agit de noms à usage privé pour répondre à des besoins spécifiques à vos applications. Ils ne doivent pas entrer en conflit avec les autres types de claims.
  • Signature : cette zone contient la signature numérique du jeton. La clé privée utilisée pour signer le jeton est stockée côté serveur.

Fonctionnement et étude de cas

De par son format compact et sa nature stateless (le jeton n’est pas stocké dans une base de données), JWT est très adapté aux transactions HTTP.
Ainsi, dans la requête d’accès à une ressource protégée, le jeton est véhiculé dans l’en-tête Authorization avec le mécanisme d’authentification Bearer :

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImRlbW8iLCJmdWxsTmFtZSI6

Le schéma ci-dessous représente un dialogue entre un client (navigateur ou autre) et une API REST (et CORS compatible) exposant 2 services :

  • un service d’authentification : POST /api/authenticate
  • un service à accès restreint retournant une liste de comptes : GET /api/restricted/accounts

Cinématique HTTP

  • dans un premier temps, le client cherche à accéder à une ressource protégée sans utiliser de jeton. Le service retourne une erreur avec un code HTTP 401 (Unauthorized)
  • dans un deuxième temps, le client s’authentifie. Le service vérifie que les vecteurs d’accréditation sont corrects, génère un jeton JWT avec une durée de vie prédéfinie puis retourne la réponse sous la forme d’un document JSON contenant le jeton (attribut token).
  • muni de ce jeton, le client accède à nouveau à la ressource protégée en le propageant dans l’entête Authorization. Le service vérifie que le jeton est effectivement valide puis retourne la liste des comptes.
    A noter que si cette requête avait été émise au delà de la durée d’expiration du jeton, le service retournerait une erreur HTTP 401 (jeton invalide).

Le code source de cette API ainsi que les instructions d’installation sont disponibles sur mon dépôt GitHub, les comptes utilisateur étant stockés dans Stormpath.

Installation et utilisation de l’API

Le mode opératoire d’installation est le suivant (testé sous Node.js 0.12) :

git clone https://github.com/ksahnine/jwt-secured-api-node.git
cd jwt-secured-api-node
npm install

Pour démarrer le conteneur de services, exécuter la commande :

npm start

Voici quelques cas d’utilisation de l’API via l’utilitaire cURL :

  • Cas 1 : accès à une ressource protégée sans jeton :
    $ curl http://localhost:8000/api/restricted/accounts
    {
      "status": "error",
      "msg": "Jeton invalide",
      "url": "/api/restricted/accounts"
    }
    
  • Cas 2 : authentification avec récupération d’un jeton :
    $ curl -X POST --data "username=demo1&password=Demo2015" http://localhost:8000/api/authenticate
    {
      "status": "ok",
      "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImRlbW8xIiwiZn"
    }
    
  • Cas 3 : accès à une ressource protégée avec un jeton valide :
    $ curl -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImRlbW8xIiwiZn" \
            http://localhost:8000/api/restricted/accounts
    [
      {
        "id": 0,
        "name": "Account 0"
      },
      {
        "id": 1,
        "name": "Account 1"
      }
    ]
    

Description de la pile technique

L’API est construite au dessus de Node.js et s’appuie les modules suivants :

  • le framework web Express pour l’implémentation des services REST/JSON et la gestion du routage
  • le module node cors pour le support CORS (compatible avec Express)
  • le middleware Passport pour la gestion de l’authentification sous Node.js, ainsi que le plugin passport-stormpath pour l’accès au gestionnaire d’identité Stormpath
  • le module jsonwebtoken pour générer et signer numériquement les jetons JWT
  • le module Express express-jwt pour valider les jetons JWT lors de l’accès aux ressources protégées
A l’attention du développeur AngularJS : vous n’êtes pas sans savoir que la spécification CORS interdit d’utiliser conjointement l’en-tête Access-Control-Allow-Origin: * et la propriété XHR withCredentials: true. Dans cette configuration, il n’est par exemple pas possible de propager un cookie de session. Dans le cas d’espèce, la solution adaptée serait de générer une entête Access-Control-Allow-Origin dynamique mais JWT présente une alternative bien plus intéressante. Nous y reviendrons dans un prochain article.

Pratique du réseau M2M SIGFOX avec Sens’it et Docker

Par Kadda SAHNINE

Publié le | 18 octobre 2015 | Pas de commentaire

Remarque : Retrouvez également cet article sur mon blog perso.

Sens'it


SIGFOX est un opérateur de télécommunication français exploitant un réseau M2M (Machine to Machine) à vocation mondiale et dédié à l’Internet des Objets.
Cette société a eu la courtoisie de me faire parvenir un exemplaire du Sens’it, un objet connecté intégrant plusieurs capteurs (température, mouvement, son) ainsi qu’un bouton poussoir.

Développé par AXIBLE technologies, partenaire de SIGFOX, Sens’it est utilisable sans connaissances informatiques pour, par exemple :

  • effectuer un relevé de température régulier
  • être notifié par SMS ou email à chaque détection de mouvement

Une API REST permet fort heureusement d’étendre le champ des possibles. On verra dans cet article comment l’utiliser pour obtenir en un clic les disponibilités de stations Vélib à proximité de son lieu de travail ou d’habitation :


Le service est dockerisé et déployé sur un Raspberry Pi model B.

Le réseau SIGFOX en bref

J’ai eu l’occasion d’expérimenter dans le cadre de projets IoT plusieurs technologies de connexion à un réseau sans fil dont :

  • le microcontrôleur avec capacités WiFi ESP8266 (Espressif), bon marché mais assez énergivore
  • le transceiver nRF24l01+ (Nordic), très bon marché et très économe en énergie, mais pas trivial à utiliser
  • le dongle 3G Huawei e173, relativement cher et très énergivore

Par rapport à d’autres solutions de connexion à un réseau sans fil, en particuler le réseau GSM, le réseau SIGFOX présente un certain nombre d’avantages comparatifs :

  • une couverture internationale
  • un faible coût d’utilisation (variable en fonction du volume de données échangées et du nombre de devices : de 1 €/an pour les gros projets jusqu’à 10 - 16 €/an)
  • des modules ou transceivers SIGFOX consommant très peu d’énergie et bon marché (compter 15 € le chip)
  • des communications sécurisées

Noter que le réseau impose un certain nombre de contraintes :

  • il s’agit d’un réseau bas débit (jusqu’à 12 bytes par message), ce qui n’est pas contraignant pour un réseau M2M
  • il n’est pas possible d’émettre plus de 140 messages par jour et par device
Note : pour en savoir beaucoup plus sur le sujet, on lira avec profit les articles de Paul Pinault (aka Disk91)

Un peu de hardware

Je n’ai pas résisté à la tentation d’ouvrir le boitier :


En zoomant, on remarquera en particulier :

  • à gauche : le microcontrôlleur PIC PIC16F1718 de Microchip
  • à droite : le transceiver CC1120 de Texas Instrument opérant sur la bande de fréquence utilisée par SIGFOX (868 MHz en Europe).

Anthonny Quérouil a écrit un billet très complet de présentation et d’utilisation du produit ainsi que de l’API REST.

Un exemple de service avec Sens’it

A titre personnel, je trouve que le bouton poussoir est une des fonctions les plus intéressantes de cet objet.
Etant parisien et utilisateur du service Vélib, je trouve l’application officielle peu pratique pour consulter les disponibilités.
Quoi de plus simple que de cliquer sur un objet connecté et de savoir instantanément combien de vélos sont disponibles dans son quartier ?
Voici une démo de l’application en action :


Le service est développé sur une stack Python (Flask) et utilise la technique du web scraping pour extraire les disponibilités sur le site velib.paris.fr.

A cet effet, j’ai utilisé l’excellente librairie BeautifulSoup.
Les notifications sont acheminées via Pushbullet, dont l’application est disponible sur une multitude de plateformes (iOS, Android, Mac, Windows, Chrome, etc.) :


Le code du service est disponible sur GitHub.

Déploiement du service

Le service est packagé sous la forme d’une image Docker ARM (ksahnine/rpi-sensit-velib), ce qui simplifiera grandement son déploiement.
Il existe plusieurs solutions pour déployer un hôte Docker sur Raspberry Pi (via ArchLinux par exemple).
Personnellement, j’utilise l’image de Hypriot, une distribution allégée de type Debian intégrant Docker 1.6, très rapide à mettre en oeuvre et fonctionnant sur n’importe quel modèle de Raspberry Pi.

  • commencez par flasher l’image sur une carte SD (ex. sous OS X) :
    $ diskutil unmountDisk /dev/disk1
    $ sudo dd if=hypriot-rpi-20150416-201537.img of=/dev/rdisk1 bs=1m
    
  • se connecter au Raspberry Pi via ssh (root/hypriot)
    $ wget https://github.com/ksahnine/sensit-sigfox/raw/master/apps/velib-callback/conf/config.yml
    
  • personnaliser le fichier de configuration ~/config.yml en renseignant le jeton d’accès de votre compte Pushbullet ainsi que l’adresse de votre lieu de travail ou d’habitation :
    # Pushbullet configuration
    pushbullet:
        api: KcY0dyPlqiu0Dp1mrH7RI30AP8O83ZYa
    
    # Address
    location: 29 rue d'Astorg, Paris
    
  • lancer l’application avec un simple docker run :
    $ docker run -d -p 5000:5000 -v ~/config.yml:/app/conf/config.yml ksahnine/rpi-sensit-velib
    
  • se connecter à l’interface d’administration de Sens’It et configurer l’URL de callback du bouton :
  • double cliquer sur le Sens’it pour recevoir une notification
Remarque : Le docker pull initial est long sur un RPi model B. Néanmoins, la taille de l’image de base utilisée peut être largement optimisée.

Eléments d’architecture

Le schéma ci-dessous décrit l’ensemble de la chaîne de liaison :

  • le double clic du Sens’it donne lieu à l’émission d’un message via le réseau SIGFOX
  • callback des serveurs d’AXIBLE vers le service hébergé sur le Raspberry Pi
  • récupération des données depuis le site velib.paris
  • envoi de la notification via Pushbullet

Quelques remarques

J’ai synthétisé quelques remarques et observations suite à mes expérimentations.

L’exploration de données Twitter

Par Kadda SAHNINE

Publié le | 1 septembre 2015 | Pas de commentaire

Remarque : Retrouvez également cet article sur mon blog perso.

Twitter


J’ai présenté dans un article les résultats de l’analyse du mot croisillon #TelAvivSurSeine, l’évènement au centre d’une polémique qui n’aurait jamais dû sortir des réseaux sociaux ni des cercles militants.

Ces résultats sont le fruit d’une analyse rationnelle et distanciée des tweets associés à ce hashtag, analyse à la portée d’un informaticien suffisamment à l’aise sous UNIX et familier du langage de programmation Python.
Je présenterai dans cet article les outils et techniques m’ayant permis d’effectuer cette analyse.
Le code est disponible dans mon repository GitHub.
Nous verrons comment extraire, explorer, synthétiser et visualiser de la connaissance à partir d’une importante masse d’information disponible sur Twitter. Ainsi nous verrons, entre autres, comment :

  • visualiser l’évolution du nombre de tweets et retweets par heure
  • identifier les comptes les plus retweetés ou mentionnés
  • identifier les comptes ayant le plus tweeté ou retweeté
  • comptabiliser les hashtags les plus utilisés
  • identifier les photos les plus diffusées
  • visualiser le réseau social constitué des 15 comptes ayant le plus (re)tweeté et des 15 comptes les plus retweetés :

Collecte des données

Vous devez évidemment disposer d’un compte Twitter. Si c’est le cas, connectez-vous sur le gestionnaire d’applications Twitter puis :

  • remplissez le formulaire de création d’une application Twitter.
  • cliquer sur l’onglet Keys and Access Token et générer le jeton d’accès (bouton Create my access token)
  • récupérez :
    • la clé de l’API (Consumer Key) et son mot de passe (Consumer Secret)
    • le jeton d’accès (Access Token) et son mot de passe (Access Token Secret)
    Note : votre profil Twitter doit être renseigné avec un numéro de téléphone valide sans quoi il ne vous sera pas possible de créer une application.

L’utilisation de l’API Twitter est plafonnée selon des critères variables.
Vous ne pourrez par exemple pas faire plus de 15 appels à la requête GET followers/ids par quart d’heure. Néanmoins, un seul appel restitue jusqu’à 5000 identifiants de followers.
Fort heureusement, la librairie tweepy propose un mode (wait_on_rate_limit) permettant au client de temporiser lorsque le quota est atteint, puis de reprendre le processus.

Par ailleurs, notez que l’API de recherche (GET search/tweets) a une profondeur de 10 jours maximum.

Je mets à disposition un script Python implémentant la collecte des tweets, à adapter selon votre contexte et après avoir renseigné les vecteurs d’accréditation (Consumer key, Consumer secret, Access token, Access token secret).

Le mode opératoire d’installation est le suivant :

pip install tweepy
git clone https://github.com/ksahnine/datascience-twitter.git

Editez le script collect.py situé dans le répertoire datascience-twitter/scripts/collect et renseignez les variables consumer_key, consumer_secret, access_token et access_token_secret avec les vecteurs d’accéditation créés plus haut.
Ensuite, vous pourrez lancer la commande suivante afin de collecter les tweets en relation avec le hashtag #TelAvivSurSeine et dumper les résultats dans le répertoire ./data :

cd datascience-twitter/scripts/collect
python ./collect.py -s "#TelAvivSurSeine" -o "./data"

Quelques préliminaires

Structure d’un tweet

Avant d’explorer les données, il est important de connaître la structure d’un tweet restitué par l’API Twitter. Elle est pleinement décrite sur le portail de dev de Twitter.
Pour vous donner une idée, voici un lien contenant un exemple complet de tweet au format JSON.
On trouvera ci-dessous une représentation très élaguée d’un tweet, ne contenant que les propriétés que nous exploiterons dans le cadre de cet article :

Voici une description des principaux champs :

  • .text : contenu du texte associé au tweet
  • .created_at : date et heure UTC de création du tweet (ou retweet)
  • .source : support utilisé (terminal Android dans l’exemple)
  • .entities.hashtags : liste des mots croisillons contenu dans le tweet
  • .entities.user_mentions : liste des comptes mentionnés dans le tweet
  • .media : liste des ressources médias contenues dans le tweet (des images par exemple)
  • .user.screen_name : nom du compte ayant tweeté (ce qui suit après le caractère @)
  • .user.followers_count : nombre d’abonnés à ce compte
  • .user.friends_count : nombre de comptes suivis
  • .retweeted_status : contenu du tweet à l’origine du retweet
  • .quoted_status : contenu du tweet à l’origine de la citation

Outils

J’ai une affinité particulière pour les outils en ligne de commande. Je vous recommande les suivants :

  • jq est un extraordinaire outil permettant de requêter des structures de données au format JSON. C’est un authentique couteau suisse absolument indispensable pour quiconque exploite des données sous ce format (c’est à dire, tout le monde…).
    Bien qu’installable via pip, je vous conseille d’installer directement la version binaire pour votre plateforme 64 bits. A ce jour, la version 1.5 est disponible sous Linux, OS X, Windows ou d’autres plateformes.
    Je trouve que cet outil permet de mieux sentir les données. Par ailleurs, il peut être très efficacement associés à d’autres commandes Unix (wc, sort, sed, awk, join etc.) jusqu’à obtenir le résultat final.
  • gnuplot est un logiciel multiplateforme produisant des représentations graphiques de données en 2D ou 3D
  • csvlook est un utilitaire permettant de formater proprement les données sous la forme de tableaux. Il est intégré au module Python csvkit dont le mode opératoire d’installation est des plus simples : pip install csvkit
Note : vérifier les prérequis d’installation en particulier sous Ubuntu

Exploration des données

Note : si vous souhaitez faire l’économie de la collecte des données et vous adonner directement à leur exploration, je mets à disposition un échantillon de données brutes (toute la journée du 10 Août 2015).
Pour récupérer le jeu de données :
git clone https://github.com/ksahnine/datascience-twitter.git
cd datascience-twitter
gunzip data/*.gz

Visualisation

Produisons le fichier courbe_tweets.csv (séparateur ,) contenant la série temporelle du nombre de tweets par tranche horaire :

$ LANG=en_US
$ jq ".created_at" data/*.json | xargs -I ? date -j -f "%a %h %d %H:%M:%S %z %Y" "?" "+%Y-%m-%d_%H:00:00" | sort | uniq -c | sed -e 's/^ *//;s/ /,/' | awk -F"," '{ print $2 "," $1}' > courbe_tweets.csv
Note : notez que l’heure UTC de création des tweets est convertie en heure locale

Une fois le fichier généré, produisons sa représentation graphique avec gnuplot :

$ gnuplot <<EOF
set datafile separator ","
set timefmt '%Y-%m-%d_%H:%M:%S'

set xdata time
set xtic rotate by -45 scale 0
set format x '%Y-%m-%d'
set ylabel "Nb tweets"

set grid ytics
set grid xtics

plot 'courbe_tweets.csv' u 1:2 with lines title 'Timeseries #TelAvivSurSeine'
EOF

Autre exemple. Produisons le fichier devices.csv contenant la distribution des tweets par device :

$ jq ".source" data/*.json | sed 's/"(<.*>)(.*)(<.*>)”/2/’ | sort | uniq -c | sort -rn | sed -e ’s/^ *//;s/ /,/’ |head -8 > devices.csv

La représentation graphique de la distribution sous la forme d’histogrammes est obtenue comme suit :

$ gnuplot <<EOF
set datafile separator ","
set style data histogram

set title "Distribution des tweets par device"
set xlabel "Devices"
set ylabel "Nb tweets"

set xtic rotate by -45 scale 0
set grid ytics
set style fill solid

plot 'devices.csv' u 1:xtic(2) notitle
EOF

Eléments statistiques

Les commandes ci-dessous permettent d’obtenir différents indicateurs statistiques sur l’ensemble du jeu de données.
On verra dans le paragraphe suivant comment obtenir ces mêmes indicateurs sur une plage de temps restreinte :

  • comptabiliser le nombre total de tweets :
    $ wc -l data/*.json
    
       76698 total
    
  • comptabiliser le nombre total de twittos (utilisateurs de Twitter) :
    $ jq '.user.screen_name' data/*.json | sort -u | wc -l
    
       16666
    
  • extraire les 5 photos les plus diffusées, avec leur nombre d’occurrences :
    $ jq 'select(.entities.media!=null)|select(.entities.media[].type="photo")|.entities.media[].media_url' data/*.json | sort | uniq -c | sort -rn | head -5
    
     478 "http://pbs.twimg.com/media/CL9DfpFWgAAZWQi.jpg"
     434 "http://pbs.twimg.com/media/CL3vnXOWgAA67oa.jpg"
     336 "http://pbs.twimg.com/media/CMC7JJxWsAAFDVD.jpg"
     294 "http://pbs.twimg.com/media/CMEr3oWWwAAYbEf.png"
     269 "http://pbs.twimg.com/media/CMEChkgWEAAIep-.jpg"
    
  • extraire les 4 types de clients Twitter les plus utilisés :
    $ jq ".source" data/*.json | sed 's/"(<.*>)(.*)(<.*>)”/2/’ | sort | uniq -c | sort -rn | head -4
    
    23210 Twitter for iPhone
    21341 Twitter for Android
    19954 Twitter Web Client
     3444 Twitter for iPad
    
  • extraire les 3 comptes les plus retweetés (c’est un indicateur d’influence) avec le nombre de RT :
    $ jq 'select(.retweeted_status!=null)|.retweeted_status.user.screen_name' data/*.json | sort | uniq -c | sort -rn | head -3
    
    1759 "ybenderbal"
    1085 "KarimaB_"
    1054 "Linformatrice"
    
  • extraire les 3 comptes les plus cités (équivalent au retweet mais moins usité) avec le nombre de citations :
    $ jq 'select(.quoted_status!=null)|.quoted_status.user.screen_name' data/*.json | sort | uniq -c | sort -rn | head -3
    
      97 "Col_Connaughton"
      52 "notstat"
      49 "Farah_Gazan"
    
  • extraire les 3 comptes les plus mentionnés (c’est un indicateur de notoriété) avec le nombre de mentions :
    $ jq ".entities.user_mentions[].screen_name" data/*.json | sort | uniq -c | sort -rn | head -3
    
    8859 "Anne_Hidalgo"
    1772 "ybenderbal"
    1500 "BrunoJulliard"
    
  • dégager les 20 sentiments dominants en comptabilisant le nombre de hashtags :
    $ jq ".entities.hashtags[].text" data/*.json | tr '[A-Z]' '[a-z]' | tr '[àâäéèêëîïôöùûü]' '[aaaeeeeiioouuu]' | sort | uniq -c | sort -rn | head -20
    
    77070 "telavivsurseine"
    5834 "apartheidsurseine"
    2880 "israel"
    2767 "gaza"
    2406 "paris"
    1868 "againsttelavivsurseine"
    1860 "parisplages"
    1668 "contretelavivsurseine"
    1666 "telaviv"
    1608 "gazasurseine"
    1606 "parislovestlv"
    1351 "palestine"
     843 "freepalestine"
     822 "bds"
     787 "parisplage"
     621 "france"
     515 "icc4israel"
     462 "hidalgo"
     434 "apartheid"
     372 "boycottisrael"
    

Filtrer par date

Utilisons le sélecteur select/match supporté par jq pour filtrer sur la date de création du tweet created_at.
Ainsi, la commande suivante permet d’identifier les 3 comptes les plus retweetés le 10 Août entre 18h et 19h59 (soit entre 16h et 18h50 heure UTC) :

$ jq 'select(.created_at|match("Mon Aug 10 1[6-7].*"))|select(.retweeted_status!=null)|.retweeted_status.user.screen_name' data/*.json | sort | uniq -c | sort -rn | head -3

 337 "Campagnebds"
 114 "LePG"
 100 "Thalwen"

Formatage des résultats avec csvlook

Voyons comment afficher les 5 comptes les plus influents (i.e les plus retweetés) sous la forme d’un tableau à 3 colonnes : le nombre de RT, le nom du compte (.user.screen_name) et la date de création du compte (.user.created_at).
On utilisera un shell imbriqué à 2 commandes :

$ (echo "Nb RT,Compte,Date Creation"; jq --raw-output 'select(.retweeted_status!=null)|[.retweeted_status.user.screen_name,.retweeted_status.user.created_at] | @csv' data/*.json | sort | uniq -c | -k1rn | sed -e 's/^ *//;s/ /,/' | head -5 ) | csvlook

|--------+---------------+---------------------------------|
|  Nb RT | Compte        | Date Creation                   |
|--------+---------------+---------------------------------|
|  1759  | ybenderbal    | Sun Mar 11 22:51:26 +0000 2012  |
|  1085  | KarimaB_      | Sat Mar 07 14:36:25 +0000 2009  |
|  1054  | Linformatrice | Thu Aug 04 02:18:52 +0000 2011  |
|  1045  | Campagnebds   | Tue Dec 15 20:33:31 +0000 2009  |
|  916   | jeremo12      | Sun Feb 26 22:54:54 +0000 2012  |
|--------+---------------+---------------------------------|

Magique ? Pas tant que ça. Décomposons la commande :

  • echo "Nb RT,Compte,Date Creation" : affiche l’entête du tableau
  • jq --raw-output 'select(.retweeted_status!=null)|[.retweeted_status.user.screen_name,.retweeted_status.user.created_at] | @csv' data/*.json :
    • filtre les éléments en ne retenant que ceux ayant une propriété retweeted_status non nulle
    • puis affiche les valeurs screen_name et created_at
    • puis formate la sortie standard en CSV
  • sort | uniq -c : tri et comptage du nombre d’occurrences (nombre de RT)
  • sort -k1rn : le flag -k1 signifie que le tri s’effectue sur la première colonne (le nombre de RT)

Plus de statistiques

Je mets à disposition un script shell implémentant plusieurs routines suffisamment génériques pour s’adonner à tous types d’explorations de données.

cd datascience-twitter/scripts/analyse

La liste des routines implémentées s’obtient en exécutant la commande : ./compute.sh.
Pour obtenir la liste des 5 comptes les plus mentionnés sur toute la période :

./compute.sh tab_mentions "../../data/*.json" ".*" 5

Pour obtenir la liste des 3 comptes les plus retweetés le 10 Août entre 18h et 19h59 heure de Paris :

./compute.sh tab_retweeted_users "../../data/*.json" "Aug 10 1[6-7]" 3

Visualiser un réseau social

Je mets à disposition un script Python reconstituant le réseau de relations entre plusieurs utilisateurs Twitter.

Si vous avez bien suivi, vous ne devriez avoir aucun mal à produire un fichier contenant les 15 comptes les plus retweetés et les 15 comptes ayant le plus tweeté.

Sinon, vous pouvez utiliser mes routines :

./compute.sh csv_tweeted_users "../../data/*.json" ".*" 15 > users.csv
./compute.sh csv_retweeted_users "../../data/*.json   " ".*" 15 >> users.csv

Reconstituons le réseau de relations entre ces utilisateurs :

./social-network.py -l users.csv

Puis générons le réseau de relations :

./social-network.py -u users.csv > ../graph/data.csv

Pour visualiser le réseau de relation, lancer la commande suivante :

cd datascience-twitter/scripts/graph
./serve.sh

Pour visualiser le résultat, ouvrir un navigateur et consulter le lien http://localhost:8000 :

open http://localhost:8000

Le graphe orienté est généré à l’aide de l’excellente librairie D3 pour laquelle j’ai consacré un article il y a 3 ans.
Les cercles représentent les comptes. Leur taille est proportionnelle à leur nombre d’abonnés.

Il s’agit d’une version très expérimentale bien sûr, mais je trouve remarquable la formation de 2 groupes distincts de tweetos dont l’un concentre les tweets défavorables à l’évènement.
Par ailleurs, on visualise bien les signes révélateurs d’astroturfing.

« go backkeep looking »

A propos de l'auteur

Kadda SAHNINE
Architecte technique Java EE
#JavaEE #Linux #vim addict #OpenSoftware #OpenHardware
Voir le profil de Kadda Sahnine sur LinkedIn

Flux RSS

Rechercher

Administration