`` tandis qu
:comment: *Mais pourquoi apprendre ça pour "scraper", me direz-vous ?*
-Parce que, pour bien récupérer les informations d'un site internet, il faut pouvoir comprendre sa structure et donc son code HTML. Les fonctions python qui servent au scrapping sont principalement construites pour vous permettre de naviguer entre les balises.
+Parce que, pour bien récupérer les informations d'un site internet, il faut pouvoir comprendre sa structure et donc son code HTML. Les fonctions python qui servent au scraping sont principalement construites pour vous permettre de naviguer entre les balises.
# Scraper avec python: le package `BeautifulSoup`
@@ -402,8 +402,6 @@ data_participants.head()
Essayez de comprendre pas à pas ce qui est fait dans les étapes qui suivent (la récupération d'informations supplémentaires en naviguant dans les pages des différents clubs).
```{python}
-#| include: false
-
import urllib
import pandas as pd
import bs4
@@ -520,6 +518,7 @@ va utilise `folium` pour celle-ci, qui est présenté dans la partie
[visualisation](#cartotp)
```{python folium1, echo = TRUE, results = "hide", message = FALSE, warning = FALSE}
+#!pip install geopandas
import geopandas as gpd
from pathlib import Path
import folium
@@ -537,11 +536,15 @@ m = folium.Map(location = center, tiles='Stamen Toner')
# I can add marker one by one on the map
for i in range(0,len(gdf)):
- folium.Marker([gdf.iloc[i]['latitude'], gdf.iloc[i]['longitude']], popup=gdf.iloc[i]['stade']).add_to(m)
+ folium.Marker([gdf.iloc[i]['latitude'], gdf.iloc[i]['longitude']], popup=gdf.iloc[i]['stade']).add_to(m)
m.fit_bounds([sw, ne])
```
+```{python, eval = FALSE}
+# Afficher la carte
+m
+```
```{python, eval = TRUE, include = FALSE}
map = m._repr_html_()
@@ -847,7 +850,7 @@ def get_cara_pokemon(pokemon_name):
cells = cells.replace('\t','').replace('\n',' ')
data[column] = cells
data['name'] = pokemon_name
- return dict(data)
+ return data
```
Vous devriez obtenir une liste de caractéristiques proche de celle-ci
@@ -965,12 +968,9 @@ L'installation de `selenium` nécessite d'avoir chromium qui est un
navigateur Google Chrome minimaliste.
La version de [chromedriver](https://sites.google.com/a/chromium.org/chromedriver/) doit être ``>= 2.36`` et dépend de la version de Chrome que vous avez sur votre poste.
-```{shell, eval = FALSE}
-# #!pip install selenium
-```
-
-
```{python, eval = FALSE}
+!pip install selenium
+
# Sur votre poste
# télécharger le chrome driver https://chromedriver.storage.googleapis.com/index.html?path=85.0.4183.83/
diff --git a/content/course/manipulation/04b_regex_TP.Rmd b/content/course/manipulation/04b_regex_TP.Rmd
index 23f590af6..2782ca042 100644
--- a/content/course/manipulation/04b_regex_TP.Rmd
+++ b/content/course/manipulation/04b_regex_TP.Rmd
@@ -39,6 +39,8 @@ knitr::knit_hooks$set(
print_badges()
```
+Ce TD est directement issu du contenu de [Xavier Dupré](http://www.xavierdupre.fr/app/teachpyx/helpsphinx/c_regex/regex.html),
+l'ancien professeur de ce cours. Il sera mis-à-jour dans le futur.
Chercher un mot dans un texte est une tâche facile, c'est l'objectif de la méthode `find()` attachée aux chaînes de caractères, étudiée dans la partie webscraping. Elle suffit également lorsque l'on cherche un mot au pluriel ou au singulier, mais il faut dans ce cas l'appeler au moins deux fois.
@@ -179,7 +181,7 @@ print(liste_emails)
{{% panel status="exercise" title="Exercice" icon="fas fa-pencil-alt" %}}
-**Exercice 1: Application directe **
+**Exercice 1: Application directe**
Recherchez les dates présentes dans la phrase suivante.
@@ -211,7 +213,7 @@ print(expression.findall(texte2))
{{% panel status="exercise" title="Exercice" icon="fas fa-pencil-alt" %}}
-**Exercice 2: Nettoyer une colonne de date de publication **
+**Exercice 2: Nettoyer une colonne de date de publication**
L'objectif général de l'exercice est de nettoyer des colonnes d'un DataFrame en utilisant des expressions régulières.
diff --git a/content/course/manipulation/04c_API_TP.Rmd b/content/course/manipulation/04c_API_TP.Rmd
index 0f55dad50..ab825cb58 100644
--- a/content/course/manipulation/04c_API_TP.Rmd
+++ b/content/course/manipulation/04c_API_TP.Rmd
@@ -33,6 +33,9 @@ summary: |
```{r setup, include=FALSE}
dir_path <- gsub(here::here(), "..", here::here("course","manipulation"))
+knitr::knit_hooks$set(
+ plot = function(x, options) modif_plot(x, options, dir_path = dir_path)
+)
```
@@ -40,245 +43,414 @@ dir_path <- gsub(here::here(), "..", here::here("course","manipulation"))
print_badges()
```
-Petite revue d'[API REST](https://fr.wikipedia.org/wiki/Representational_state_transfer).
+# Introduction : Qu'est-ce qu'une API ?
-
-## Définition :
+## Définition
-API, à part que ce mot qui vaut 5 au scrabble, c'est quoi au juste ?
+Pour expliquer le principe d'une API, je vais reprendre le début de
+la fiche dédiée dans la documentation collaborative
+[utilitR](https://www.book.utilitr.org/api.html) que je recommande de lire :
+> Une *Application Programming Interface* (ou API) est une interface de programmation qui permet d’utiliser une application existante pour restituer des données. Le terme d’API peut être paraître intimidant, mais il s’agit simplement d’une façon de mettre à disposition des données : plutôt que de laisser l’utilisateur consulter directement des bases de données (souvent volumineuses et complexes), l’API lui propose de formuler une requête qui est traitée par le serveur hébergeant la base de données, puis de recevoir des données en réponse à sa requête.
+>
+> D’un point de vue informatique, une API est une porte d’entrée clairement identifiée par laquelle un logiciel offre des services à d’autres logiciels (ou utilisateurs). L’objectif d’une API est de fournir un point d’accès à une fonctionnalité qui soit facile à utiliser et qui masque les détails de la mise en oeuvre. Par exemple, l’API Sirene permet de récupérer la raison sociale d’une entreprise à partir de son identifiant Siren en interrogeant le référentiel disponible sur Internet directement depuis un script R, sans avoir à connaître tous les détails du répertoire Sirene.
+>
+> À l’Insee comme ailleurs, la connexion entre les bases de données pour les nouveaux projets tend à se réaliser par des API. L’accès à des données par des API devient ainsi de plus en plus commun et est amené à devenir une compétence de base de tout utilisateur de données.
+>
+> [`utilitR`](https://www.book.utilitr.org/api.html)
-API signifie Application Programming Interface. Le mot le plus important est “interface”, et c’est le mot le plus simple, car nous utilisons tous des interfaces.
+## Avantages des API
-Bon, et une interface ?
+A nouveau, citons la documentation [utilitR](https://www.book.utilitr.org/api.html)
-> Définition Larousse : "Une interface est un dispositif qui permet des échanges et interactions entre différents acteurs"
+Les API présentent de multiples avantages :
-Pour faire simple, une API est un moyen efficace de faire communiquer entre elles deux applications : concrètement, un fournisseur de service met à disposition des développeurs une interface codifiée, qui leur permet d'obtenir des informations à partir de requêtes.
+> * Les API rendent les programmes plus reproductibles. En effet, grâce aux API, il est possible de mettre à jour facilement les données utilisées par un programme si celles-ci évoluent. Cette flexibilité accrue pour l’utilisateur évite au producteur de données d’avoir à réaliser de multiples extractions, et réduit le problème de la coexistence de versions différentes des données.
+> * Grâce aux API, l’utilisateur peut extraire facilement une petite partie d’une base de données plus conséquente.
+> * Les API permettent de mettre à disposition des données tout en limitant le nombre de personnes ayant accès aux bases de données elles-mêmes.
+> * Grâce aux API, il est possible de proposer des services sur mesure pour les utilisateurs (par exemple, un accès spécifique pour les gros utilisateurs).
+>
+> [`utilitR`](https://www.book.utilitr.org/api.html)
-Sans rentrer dans le détail technique, le dialogue ressemble à : "envoie moi ton adresse sous la forme X = rue, Y = Ville, Z = Pays" et moi, en retour, je t'enverrai le code à afficher sur ton site pour avoir la carte interactive.
+## Utilisation des API
+Citons encore une fois
+la documentation [`utilitR`](https://www.book.utilitr.org/api.html)
+> Une API peut souvent être utilisée de deux façons : par une interface Web, et par l’intermédiaire d’un logiciel (R, Python…). Par ailleurs, les API peuvent être proposées avec un niveau de liberté variable pour l’utilisateur :
+>
+> * soit en libre accès (l’utilisation n’est pas contrôlée et l’utilisateur peut utiliser le service comme bon lui semble) ;
+> * soit via la génération d’un compte et d’un jeton d’accès qui permettent de sécuriser l’utilisation de l’API et de limiter le nombre de requêtes.
+>
+> [`utilitR`](https://www.book.utilitr.org/api.html)
-
+De nombreuses API nécessitent une authentification, c'est-à-dire un
+compte utilisateur afin de pouvoir accéder aux données.
+Dans un premier temps,
+nous regarderons exclusivement les API ouvertes sans restriction d'accès.
+Certains exercices et exemples permettront néanmoins d'essayer des API
+avec restrictions d'accès.
-
-## Les API qui existent
+# Requêter une API
+## Principe général
-De plus en plus de sites mettent à disposition des développeurs et autres curieux des API.
+> L’utilisation de l’interface Web est utile dans une démarche exploratoire mais trouve rapidement ses limites, notamment lorsqu’on consulte régulièrement l’API. L’utilisateur va rapidement se rendre compte qu’il est beaucoup plus commode d’utiliser une API via un logiciel de traitement pour automatiser la consultation ou pour réaliser du téléchargement de masse. De plus, l’interface Web n’existe pas systématiquement pour toutes les API.
+>
+> Le mode principal de consultation d’une API consiste à adresser une requête à cette API via un logiciel adapté (R, Python, Java…). Comme pour l’utilisation d’une fonction, l’appel d’une API comprend des paramètres qui sont détaillées dans la documentation de l’API.
+>
+> [`utilitR`](https://www.book.utilitr.org/api.html)
-Pour en citer quelques-uns :
-- Twitter : https://dev.twitter.com/rest/public
-- Facebook : https://developers.facebook.com/
-- Instagram : https://www.instagram.com/developer/
-- Spotify : https://developer.spotify.com/web-api/
+Voici les éléments importants à avoir en tête sur les requêtes (j'emprunte encore
+à [`utilitR`](https://www.book.utilitr.org/api.html)):
+* Le __point d’entrée__ d’un service offert par une API se présente sous la forme d’une URL (adresse web). Chaque service proposé par une API a sa propre URL. Par exemple, dans le cas de l’OpenFood Facts,
+l'URL à utiliser pour obtenir des informations sur un produit particulier (l'identifiant `737628064502`) estg https://world.openfoodfacts.org/api/v0/product/737628064502.json
+* Cette URL doit être complétée avec différents paramètres qui précisent la requête (par exemple l’identifiant Siren). Ces paramètres viennent s’ajouter à l’URL, souvent à la suite de `?`. Chaque service proposé par une API a ses propres paramètres, détaillés dans la documentation.
+* Lorsque l’utilisateur soumet sa requête, l’API lui renvoie une réponse structurée contenant l’ensemble des informations demandées. Le résultat envoyé par une API est majoritairement aux formats JSON ou XML (deux formats dans lesquels les informations sont hiérarchisées de manière emboitée). Plus rarement, certains services proposent une information sous forme plate (de type csv).
-Ou encore :
+Du fait de la dimension hiérarchique des formats JSON ou XML, le résultat n’est pas toujours facile à récupérer mais
+`python` propose d'excellents outils pour cela (meilleurs que ceux de `R`). Certains packages, notamment `json`, facilitent l’extraction de champs d’une sortie d’API. Dans certains cas, des packages spécifiques à une API ont été créés pour simplifier l’écriture d’une requête ou la récupération du résultat. Par exemple, le package
+[pynsee](https://github.com/InseeFrLab/Py-Insee-Data/tree/master/pynsee)
+propose des options qui seront retranscrites automatiquement dans l'URL de
+requête pour faciliter le travail sur les données Insee.
-- Pole Emploi : https://www.emploi-store-dev.fr/portail-developpeur-cms/home.html
-- SNCF : https://data.sncf.com/api
-- Banque Mondiale : https://datahelpdesk.worldbank.org/knowledgebase/topics/125589
-
-pour beaucoup d'entre elles, il faut créer un compte utilisateur afin de pouvoir accéder aux données (c'est notamment le cas pour les réseaux sociaux), nous regarderons en cours seulement les API ouvertes sans restriction d'accès.
-
-
-## Comment parler à une API ?
+## Exemple avec l'API de la Banque Mondiale
-La plupart des API donnent des exemples par communiquer avec les données présentes sur le site.
+Avec l'API de la Banque mondiale, voici comme s'écrit une requête :
-Simplement, il faut trouver l'url qui renvoit les données que vous souhaitez avoir
+> http://api.worldbank.org/v2/countries?incomeLevel=LMC
-Par exemple, avec l'API de la Banque mondiale, voici comme s'écrit une requête pour les données de la Banque Mondiale :
+1. Le point d'entrée est l'URL
Vente en {annee}
Prix {prix:.0f} €".format(
+ num = s['num_voie_clean'],
+ voie = s["voie"],
+ annee = s['date_mutation'].split("-")[0],
+ prix = s["valeur_fonciere"]),
+ axis=1)
+
+center = ventes[['lat', 'lon']].mean().values.tolist()
+sw = ventes[['lat', 'lon']].min().values.tolist()
+ne = ventes[['lat', 'lon']].max().values.tolist()
+
+m = folium.Map(location = center, tiles='Stamen Toner')
+
+# I can add marker one by one on the map
+for i in range(0,len(ventes)):
+ folium.Marker([ventes.iloc[i]['lat'], ventes.iloc[i]['lon']],
+ popup=ventes.iloc[i]['text'],
+ icon=folium.Icon(color=ventes.iloc[i]['map_color'], icon=ventes.iloc[i]['icon'])).add_to(m)
+
+m.fit_bounds([sw, ne])
```
+```{python, eval = FALSE}
+# Afficher la carte
+m
+```
+
+```{python, include = FALSE}
+map = m._repr_html_()
+```
+
+```{r, echo = FALSE, results = 'asis'}
+cat(py$map)
+```
+
+{{% /panel %}}
+
+
+
+
# Exercices supplémentaires
+{{% panel status="exercise" title="Exercise" icon="fas fa-pencil-alt" %}}
-## Retrouver des produits dans l'openfood facts :pizza:
+**Exercice 1 : Retrouver des produits dans l'openfood facts :pizza:**
Voici une liste de code-barres:
`3274080005003, 5449000000996, 8002270014901,
3228857000906, 3017620421006, 8712100325953`
Utiliser l'[API d'openfoodfacts](https://world.openfoodfacts.org/data)
-(l'API, pas depuis le CSV)
+(l'API, pas depuis le CSV !)
pour retrouver les produits correspondant
et leurs caractéristiques nutritionnelles.
Le panier paraît-il équilibré ? :chocolate_bar:
+Pour vous aidez, vous pouvez regarder une exemple de structure du json ici : https://world.openfoodfacts.org/api/v0/product/3274080005003.json en particulier la catégorie `nutriments`.
+
```{r, include = FALSE}
library(reticulate)
```
```{python}
+#| include: false
+
import json
import requests
import pandas as pd
+```
+
+
+```{python}
+#| include: false
+# Paramètres nécessaires
df = pd.DataFrame([3274080005003, 5449000000996, 8002270014901,
3228857000906, 3017620421006, 8712100325953], columns = ['code_ean'])
nutri = ['energy_100g', 'nutriscore_grade', 'nova_group', 'fat_100g', 'saturated-fat_100g', 'carbohydrates_100g', 'sugars_100g', 'salt_100g', 'fiber_100g', 'proteins_100g', 'calcium_100g', 'iron_100g', 'sodium_100g', 'cholesterol_100g']
cols_api = ['code', 'product_name', 'categories', 'categories_tags'] + ["nutriments.{}".format(i) for i in nutri]
+```
+
+```{python}
+#| include: false
+
def get_products_api(barcode, col = cols_api):
- res = requests.get("https://world.openfoodfacts.org/api/v0/product/{}.json".format(str(barcode)))
+ url = "https://world.openfoodfacts.org/api/v0/product/{}.json".format(str(barcode))
+ #print(url)
+ res = requests.get(url)
results = res.json()
product = results["product"]
openfood = pd.json_normalize(product)
openfood = openfood[list(set(col) & set(openfood.columns))]
return openfood
+# Exemple
+get_products_api(3274080005003, col=["code","nutriments.fat_100g"])
+```
+
+
+```{python}
+#| include: false
+
openfood = [get_products_api(barcode) for barcode in df['code_ean'].dropna().astype(str).unique()]
openfood = pd.concat(openfood)
openfood.head(10)
@@ -287,10 +459,15 @@ openfood.head(10)
Récupérer l'URL d'une des images et l'afficher dans votre navigateur. Par exemple,
celle-ci:
-```{python, echo = FALSE}
+
+```{python}
+#| echo: false
+
url_image = get_products_api(5449000000996, col = ["image_front_small_url"])["image_front_small_url"].iloc[0]
```
```{r, echo = FALSE}
knitr::include_graphics(py$url_image)
```
+
+{{% /panel %}}