Cette newsletter vous est envoyée par l’agence Predict Boost et les formations ML Academy. Pour tout sujet concernant vos données, vous pouvez prendre rendez vous via notre site internet. Enfin, notre dernier article sur l’accélération de code Python !
Newsletters spéciales en Décembre, nous allons nous intéresser au développement pratique d'une application web, de A à Z, avec scraping de Tinder
Cette semaine, focus sur la base de données, et le scraper. Une semaine plus technique avec un aperçu du code que j'utilise !
La gestion des données
On l'a vu la semaine dernière, nous avons deux sources de données dans ce projet : le frontend qui récupère des informations utilisateur d'une part, et le scraper, qui renvoie des informations de Tinder d'autre part.
Nous sommes passés rapidement sur les concepts importants que nous allons utiliser : l'usage de repositories et le CRUD. Mais cette semaine nous allons voir la mise en place d'une base de données. On utilisait un CSV naïf pour stocker les informations jusque là, mais c'est une mauvaise idée.
Pourquoi cela ? Voici quelques éléments de réflexion :
Écrire dans un CSV ne rend pas l'accès aux données plus simples, surtout si elles sont sur une machine distante. Bien au contraire !
Côté Python, cela demande encore de coder des classes d'interfaces (repository) pour avoir une infrastructure robuste, nous allons y revenir.
On perd en capacité de gestion fine de nos données : modification d'entrées dans la base, backup etc.
J'ai pensé à Postgre, pour avoir une base SQL mais j'ai finalement choisi MongoDB.
C'est une base de données moderne, No-sql. Les documents remplacent les tables, et peuvent être liés les uns aux autres. Les requêtes se font facilement et efficacement.
Concrètement, voici un lien pour l'installer sous Mac OS - l'installation linux est similaire.
L'idéal est d'installer avec Brew ce qui peut l'être. Pour ceux qui ne connaissent pas c'est une gestionnaire de paquets comme apt-get sous Linux.
Une petite erreur au passage, comme on en trouve des dizaines dans ce genre de projet : j'ai eu l'erreur brew install mongodb
Error: unknown or unsupported macOS version: :mountain_lion
Je ne suis même pas sous mountain lion !
En cherchant un peu, on trouve :
On a alors installé MongoDB.Pour toute utilisation dans le code il faudra l'exécuter en local, en précisant le chemin d'un dossier data/db où les données seront stockées.
Maintenant côté code :
Pour illustrer la suite, je mets du code que j'utilise vraiment dans mon projet. Mais simplifié pour rester compréhensible.
Pour utiliser Mongo on va avoir besoin de trois aspects :
Se connecter à la base.
La requêter : Mongo fonctionne donc à l'aide de Documents.
Accéder à ces fonctionnalités au moment de traiter la request (POST, GET etc).
Pour faire tout cela nous allons créer une classe MongoDBEngine, notre "engine", qui permettra de faire les deux premières opérations. Qu'on ait choisi Mongo ou une autre base, le schéma suivant serait le même.
L'accès à la base
Pour le dernier point, en utilisant Pyramid, le mieux est de d'adjoindre cet engine à la request. En effet, l'API étant REST, c'est la chose qui sera accessible à chaque appel.
Anticipation ! Nous aurons plus tard besoin d'autres outils que juste la base de données : le scraper, et peut-être encore d'autres routines. Il est alors astucieux de créer une classe Container, qui contiendra les contiendra tous, et sera adjointe à la request.
On note la présence de notre service de scraping, qui a également besoin d'accéder à la base de données.
On l'adjoint à la request au démarrage de l'API :
L'étape de configuration permet de déterminer facilement, suivant un flag de lancement si l'api est lancée en local, - auquel cas l'URI Mongo sera alors de type
mongodb://localhost:27017/my_local_db -
sur le serveur de production, ou encore en test (on y reviendra).
Les Documents
A cette étape on a accès à la base de données. Nous construisons donc une classe de Document Mère, puis un premier Document pour nos clients.
Ce sont ces deux classes qui permettront de requeter la base ensuite. On pourrait les utiliser directement dans le code.
Mais nous avons choisi d'implémenter la logique CRUD pour faire une abstraction supplémentaire : le repository. Pour le customer cela donne une architecture de ce type :
Nous enrichissons ensuite notre MongoEngine de ce repository, qui permettra ensuite de faire les appels :
Pour finir par donner la vue POST suivante :
On y voit tous les éléments vus plus haut:
La request nous donne accès au container.
Le container permet d'accéder à notre MongoEngine.
Le repository qu'il contient fait une interface propre avec la base.
Quelques avantages de cette structure :
Il est simple d'ajouter de nombreux documents.
Changer de type de base est aussi très simple : on n'a qu'à recoder les classes repositories et documents.
Maintenant, comment monitorer ce qui se passe dans la base ? Rien de plus simple avec
Robo mongo. On peut facilement voir nos différentes bases et les modifier.
Avec tout cela on est parés côté base de données. A part les test ! Mais c'est pour plus tard.
Le scraper
L'une des étapes clef de ce projet. Sans rentrer dans les détails du code, il y a plusieurs façons de le faire.
Trois grandes librairies déjà :
Beautiful soup : le plus user friendly.
Scrapy, le plus professionnel.
Selenium, le troisième homme. A l'origine développé pour tester les sites, en simulant le comportement d'un utilisateur.
Il existe de multiples façon de scraper un site :
Observer une page (toujours avec l'outils développeur) pour parfois observer quelle requête est effectuée pour obtenir la donnée.
Lire le code HTML de la page pour directement extraire l'info que l'on souhaite, avec des regex ou autre technique plus complexe.
Et d'autres encore. Pour mon cas sur Tinder, lorsque j'essaie de charger une page dans le Shell Scrapy, très pratique pour une investigation rapide, j'ai eu l'erreur You need to enable Javascript.
Cela signifie que le code HTML de la page est en fait généré au chargement par du code Javascript, exécuté par le navigateur.
Solution : utiliser un simulateur de navigateur, qui va se charger de faire la génération de code à la volée. On en parle ici.
Mais pour faire plus simple, nous avons utilisé Selenium, qui permet facilement aussi de simuler un navigateur, et donc de contourner le problème.
Coté intégration à l’API, on l’a vu plus haut : c'est une classe instanciée au démarrage de l'API, adjointe au container et accessible au moment de la request.
Dans les faits j'ai utilisé APscheduler pour lancer un Background scheduler, qui monitore ma base de données pour ensuite aller scraper les informations utiles.
C'est tout pour cette semaine ! N’hésitez pas à donner votre avis en répondant à ce mail. Si vous aimez les détails technique, ou au contraire vous préférez des présentations plus générales. Votre avis nous intéresse !
❤️