Récemment j'ai voulu ré-utilisé l'API Wikipedia avec Python. Mais celle-ci avait tellement évoluée, que ce soit l'API ou l'organisation de la BDD Wikipedia, que mon projet était envahi d'erreurs, que ce soit sur la pertinence des résultats, du fait de DisambiguationError
ou d'autres exceptions.PageError
...
J'ai donc décidé de revoir complètement ma façon d'utiliser l'API Wikipedia, ci-dessous un petit retour d'expérience.
Ce n'est pas parfait, mais ça permet de maximiser le retour de résultats, de vérifier leur pertinence, de les mettre en forme et d'éviter un certain nombre de messages d'erreur. Et surtout, ça donne une base solide sur laquelle améliorer encore sa façon d'utiliser l'API.
Les versions utilisées sont Python 3.9 et Wikipedia 1.4.
Et pour les plus pressés, le code complet est sur GitHub !
Que cherche-t-on ?
Voici une première façon d'utiliser l'API Wikipedia.
Ici je cherche le texte Aiguille Dibonna, une montagne du massif des Écrins, dans les Alpes françaises :
import wikipedia wikipedia.set_lang("fr") summary = wikipedia.summary("Aiguille Dibona", sentences=10) print(summary)
Si vous testez ce code, vous verrez qu'il fonctionne parfaitement. D'autant qu'un article Wikipédia existe et est très exactement intitulé... Aiguille Dibona 😎⛰️👴
https://fr.wikipedia.org/wiki/Aiguille_Dibona
L'aiguille Dibona est une aiguille culminant à 3 131 m d'altitude dans le massif des Écrins...
== Histoire ==
1913 - Première ascension, peu difficile par l'arête nord...
Mais si vous enlevez le mot Aiguille, et ne cherchez que le mot Dibona (allez-y, testez...) :
Dipoena est un genre d'araignées 🕷️ aranéomorphes de la famille des Theridiidae.
== Distribution ==
Les espèces de ce genre se rencontrent en Amérique... 😭😵😭
Il serait donc bel et bon de préciser ce que l'on cherche, par exemple en utilisant une expression généralisant le domaine de recherche. Exemple ci-dessous an ajoutant à la recherche la chaîne montagne (attention, jeu de mot 😜 !) :
import wikipedia wikipedia.set_lang("fr") chercherMot = 'Dibona' aide = 'montagne' chercher = aide + ' ' + chercherMot summary = wikipedia.summary(chercher, sentences=10) print(summary)
Et là OK, on retrouve notre jolie montagne !
Qui cherche-t-on ?
Reprenons notre 1er exemple mais en cherchant cette fois une montagne d'un nom très générique, exemple : l'Ourson.
import wikipedia wikipedia.set_lang("fr") summary = wikipedia.summary("l'Ourson", sentences=10) print(summary)
wikipedia.exceptions.DisambiguationError: "Ours (homonymie)" may refer to:
Ursidés
ours
ours
ours
ours
Ours de Digne...
Wikipédia hésite fortement et déclenche une DisambiguationError
: plusieurs articles Wikipédia peuvent faire référence à votre recherche (on peut plus ou moins parler d'articles homonymes).
Bien sûr nous pourrions lancer notre recherche au hasard sur l'un de ces articles :
import wikipedia import random wikipedia.set_lang("fr") try: summary = wikipedia.summary("L'Ourson", sentences=3) except wikipedia.DisambiguationError as e: print('\nAttention : DisambiguationError !') s = random.choice(e.options) summary = wikipedia.summary(s) print(summary)
Ok, au hasard, ça marche... Mais ce n'est pas très précis 😡
Le bug BeautifulSoup
Et en plus on a une erreur GuessedAtParserWarning
. Elle doit venir d'un conflit avec la bibliothèque BeautifulSoup. N'étant pas résolue à ma connaissance, je me contente de l'ignorer :
import warnings warnings.catch_warnings() warnings.simplefilter('ignore')
Et du coup... Qui cherche-t-on ?
Ok pour le GuessedAtParserWarning
, mais quid de nos résultats hasardeux ? On est content ? Pas du tout, nous allons donc explorer un à un ces différents articles :
import wikipedia import warnings warnings.catch_warnings() warnings.simplefilter('ignore') wikipedia.set_lang("fr") try: summary = wikipedia.summary("L'Ourson", sentences=3) print(summary) except wikipedia.DisambiguationError as e: for p in e.options: try: summary = wikipedia.summary(p, sentences=3) print('\n' + summary) except: pass
Ursins est une commune suisse du canton de Vaud...
Tours (prononcé [tuʁ] ) est une ville située dans l'Ouest de la France...
Urse d’Auxerre († 507 ou 508) ou Ursus ou Ours, est le 10e évêque d'Auxerre...
Ah ! Il est donc possible d'itérer sur chaque article homonyme et de récupérer leur résumé Wikipédia.
Qu'avons nous trouvé ?
De même qu'au début de cet article nous avons ajouté une précision sur le domaine de recherche pour aider l'API, nous pouvons aussi utiliser un test logique pour vérifier la pertinence des résultats. Dans mon cas par exemple, je compte chercher des articles Wikipédia sur des sommets montagneux du massif des Écrins. Et bien je vais vérifier si le texte massif des Écrins est présent dans mes résultats :
import wikipedia import warnings warnings.catch_warnings() warnings.simplefilter('ignore') wikipedia.set_lang("fr") try: summary = wikipedia.summary("L'Ourson", sentences=3) except wikipedia.DisambiguationError as e: for p in e.options: try: print(p) summary = wikipedia.summary(p, sentences=3) if str('massif des Écrins').lower() in str(summary).lower(): break if not str('massif des Écrins').lower() in str(summary).lower(): summary = 'Pas pertinent' except: pass print(summary)
Bouquet final
Bien, je ne vais pas vous faire patienter plus longtemps, ci-dessous un code qui va tirer parti de ce qu'on appris au-dessus, à savoir :
- L'aide à la recherche
- La vérification des résultats
- La gestion des articles homonymes
Mais à cela nous allons ajouter :
- La gestion des pages introuvables (
exceptions.PageError
) - La gestion de l'absence de connection internet (
exceptions.ConnectionError
) - La mise en forme du résultat
- Le raccourcissement du résultat
import wikipedia import requests import warnings import re warnings.catch_warnings() warnings.simplefilter('ignore') wikipedia.set_lang('fr') # On précise ici la chaîne à chercher car on l'utilisera sans doute plusieurs fois chercherMot = "Grand Pic de la Meije" # Chaîne pour aider à trouver l'article aide = 'montagne' # Chaîne pour vérification du résultat # On la précise ici car on l'utilisera sans doute plusieurs fois chaineTemoin = 'Massif des Écrins' # Nombre de phrases à récupérer # On le précise ici car on l'utilisera sans doute plusieurs fois numberPhrase = 10 # Nombre de lettres à récupérer numberLetter = 500 myWikiContent = 'Pas pertinent' if chercherMot != '' and chercherMot != None : chercher = aide + ' ' + chercherMot print('\nChercher :', chercher) try: myWikiContent = wikipedia.summary(chercher, sentences=numberPhrase) # Vérifier la pertinence du résultat if str(chaineTemoin).lower() in str(myWikiContent).lower(): pass else: myWikiContent = 'Pas pertinent' except wikipedia.exceptions.PageError as e: myWikiContent = 'Pas pertinent' except requests.exceptions.ConnectionError as e: myWikiContent = 'Pas pertinent' # Gestion des DisambiguationErrors except wikipedia.DisambiguationError as e: for p in e.options: print('Option testée : ' + p) try: myWikiContent = wikipedia.summary(p, sentences=numberPhrase) # Vérifier la pertinence du résultat if str(chaineTemoin).lower() in str(myWikiContent).lower(): break if not str(chaineTemoin).lower() in str(myWikiContent).lower(): myWikiContent = 'Pas pertinent' except wikipedia.DisambiguationError as e: myWikiContent = 'Pas pertinent' except wikipedia.exceptions.PageError as e: myWikiContent = 'Pas pertinent' except requests.exceptions.ConnectionError as e: myWikiContent = 'Pas pertinent' # Mise en forme du résultat myWikiContent = re.sub('==(.+)==', '', myWikiContent) myWikiContent = re.sub('\n\n', '\n', myWikiContent) myWikiContent = re.sub('\n\n', '\n', myWikiContent) myWikiContent = re.sub('\. ', '.\n', myWikiContent) myWikiContent = re.sub('\[réf\.\n', ' [réf. ', myWikiContent) # Raccourcissement du résultat if len(myWikiContent) > numberLetter: myWikiContent = myWikiContent[:numberLetter] + '...' print('\n' + str(myWikiContent)) if len(myWikiContent) < numberLetter: print('\n' + str(myWikiContent))
Testez le code ci-dessus en recherchant le sommet nommé L'Ourson par exemple, et en vidant l'aide à la recherche, vous comprendrez mieux son intérêt !
😎👨💻🕵️♂️🤗