Interroger l’API HAL avec Python

Il est certainement inutile de présenter l’archive ouverte multidisciplinaire HAL et son interface en ligne. Un usage moins visuellement saillant de cette archive est qu’il est également possible d’interagir avec sa base de données via une API, et notamment de l’interroger pour y effectuer des recherches selon divers critères puis de récupérer les résultats dans différents formats de données structurées.

Vous pouvez tout à fait utiliser Python pour interroger l’API de HAL et traiter les résultats obtenus.

Un script comportant différents exemples de requêtes et fonctions est mis à disposition sur Github et Gitlab pour accompagner cet article.

La recherche sur HAL par l’intermédiaire de son API est peut-être moins intuitive (du moins, dans un premier temps) mais demeure au final assez proche de l’interrogation de la base en passant par l’interface visuelle. Elle s’effectue suivant ces trois étapes :

  1. Construire la requête (sélectionner les termes et critères de recherche, restreindre ou non à un portail ou une collection…).
  2. Soumettre la requête.
  3. Récupérer les résultats au format de votre choix (ce qui équivaut à utiliser le bouton Exporter de l’interface visuelle).

La grande différence est que lors de l’utilisation de l’API, davantage de choix sont à faire dès la formulation de la requête.

Construire la requête

La construction de la requête constitue en effet la partie la plus importante du travail ici, Python servant finalement surtout à la relayer. Dans un premier temps, il n’est donc pas nécessaire de se soucier du script dans son ensemble, les résultats que vous obtiendrez dépendent uniquement de la formulation de votre requête. Celle-ci permet de spécifier :

  • Votre ou vos termes de recherche.
  • À quels champs (titre, texte, auteur, institution…) doivent s’appliquer ces termes de recherche.
  • Dans quel référentiel et/ou quelle collection la recherche doit être effectuée.
  • Quelles données et métadonnées récupérer dans les résultats.
  • Le nombre maximal de résultats que vous souhaitez obtenir.
  • Comment ces résultats doivent être triés et/ou filtrés.
  • Et sous quel format les retourner.

Consulter la documentation est indispensable, et il faut aussi et surtout avoir une idée assez claire de ce que vous voulez rechercher.

Pour l’exemple, imaginons que je cherche à savoir si d’autres membres de mon unité ont des publications HAL à propos de Python1. La documentation consacrée à la recherche via l’API HAL fournit son point d’entrée par défaut, qui constituera la base de la requête, que j’associe ici à la variable ma_requete.

ma_requete = "http://api.archives-ouvertes.fr/search/"

Si mon but est de rechercher des publications à propos de Python, je vais bien entendu utiliser Python comme terme de recherche à un moment donné. Mais comme je ne veux ici que des résultats concernant une unité donnée, il serait pertinent de restreindre la requête (et donc ses résultats) au CRLAO. Celui-ci dispose d’une collection HAL, intitulée CRLAO.

ma_requete = "http://api.archives-ouvertes.fr/search/CRLAO/"

La partie de HAL à prendre en compte étant maintenant correctement définie, il est temps de renseigner les critères. C’est ici que commence ce que l’API considère comme la requête à proprement parler, elle est à précéder par q, son seul paramètre indispensable. Avec Python comme terme de recherche :

ma_requete = "http://api.archives-ouvertes.fr/search/CRLAO/?q=python"

En ajoutant le terme de recherche de cette façon, on ne cible pas un champ en particulier. Ce qui n’empêchera pas la requête d’aboutir, mais puisque pour cet exemple je voudrais trouver des articles dont Python constitue le sujet principal, il est peut-être plus prudent de focaliser ma recherche sur le titre.

Pour trouver comment préciser le champ auquel appliquer un terme de recherche, vous pouvez consulter cette page de la documentation, qui contient la liste des champs disponibles2. Le champ correspondant au titre s’appelle title_t, c’est celui que je vais choisir ici.

ma_requete = "http://api.archives-ouvertes.fr/search/CRLAO/?q=title_t:python"

J’ai présupposé que cette recherche renverrait peu de résultats, mais après tout je ne connais pas de manière exhaustive les publications des membres de mon laboratoire, et il se pourrait qu’un(e) de mes collègues ait en fait publié des milliers d’articles consacrés à Python sans que je sois au courant.

Il est possible d’ajouter des critères de recherche en les combinant avec &, ce que je vais ici faire pour préciser un nombre maximal de résultats à retourner. Le paramètre correspondant s’appelle rows.

ma_requete = "http://api.archives-ouvertes.fr/search/CRLAO/?q=title_t:python&rows=100"

Par confort, j’apprécie de voir les résultats les plus récents en début de liste. Le classement s’effectue avec sort et peut porter sur divers champs3 ; je vais ici choisir la date de dépôt sur HAL (submittedDate_tdate). Attention, il faut préciser si l’ordre doit être ascendant (asc) ou descendant (desc).

ma_requete = "http://api.archives-ouvertes.fr/search/CRLAO/?q=title_t:python&rows=100&sort=submittedDate_tdate desc"

En l’état, cette requête va rechercher dans les publications de la collection CRLAO (CRLAO) celles qui contiennent python dans leur titre (?q=title_t:python) et retourner un maximum de 100 résultats (rows=100) triés par date de dépôt en ordre descendant (sort=submittedDate_tdate desc).

En l’absence de précision, le format des résultats est laissé par défaut et sera donc du JSON. Il est possible de choisir d’autres formats, mais je reviendrai sur cette question un peu plus loin.

Envoyer la requête à l’API

L’envoi de la requête se fera à l’aide de la librairie requests, qui sera donc à importer en début de script.

Si vous avez lu les articles de ce carnet montrant du web scraping (notamment Produire un corpus web format XML en 15 lignes de code), vous avez déjà rencontré requests.get(url) qui permet d’accéder à une URL. Ici requests.get() va nous servir à soumettre la requête (stockée dans la variable ma_requete).

Le script ressemble à ceci :

import requests

ma_requete = "http://api.archives-ouvertes.fr/search/CRLAO/?q=title_t:python&rows=100&sort=submittedDate_tdate desc"
reponse = requests.get(ma_requete)

S’il est exécuté, voici ce que contiendra la variable reponse :

<Response [200]>

Il s’agit d’un objet de la classe requests.models.Response dont la valeur correspond au code de statut de la réponse renvoyée. En l’occurrence, 200 indique que la requête a bien reçu une réponse.

Récupérer les résultats

Pour récupérer les résultats, il suffit d’appeler l’attribut .text de cet objet, soit reponse.text pour les noms de variables utilisés ici.

En passant la valeur de rows à 3 dans la requête construite ci-dessus pour éviter de produire un résultat trop long4, la valeur de reponse.text est la suivante :

'{"response":{"numFound":10,"start":0,"docs":[{"docid":3523195,"label_s":"Alexander Delaporte. Utiliser TinySegmenter avec Python. 2022, https://tekipaki.hypotheses.org/2015. ⟨hal-03523195⟩","uri_s":"https://hal.archives-ouvertes.fr/hal-03523195"},{"docid":3523158,"label_s":"Alexander Delaporte. Lire (et modifier) un fichier XML avec Python. 2021, https://tekipaki.hypotheses.org/1906. ⟨hal-03523158⟩","uri_s":"https://hal.archives-ouvertes.fr/hal-03523158"},{"docid":3521321,"label_s":"Alexander Delaporte. Navigation web automatique avec Python. 2021, https://tekipaki.hypotheses.org/1475. ⟨hal-03521321⟩","uri_s":"https://hal.archives-ouvertes.fr/hal-03521321"}]}}\n'

L’envoi de la requête a fonctionné et la réponse reçue semble cohérente, puisqu’il s’agit bien de publications déposées par un membre de mon unité (en l’occurrence, moi-même) dont le titre contient le terme python.

Les données sont au format JSON, qui est le format par défaut des réponses de l’API HAL. Ce n’est pas très agréable à lire tel quel, mais ces données peuvent être traitées automatiquement sans problème. Le script téléchargeable comporte un exemple de traitement simple d’une réponse format JSON avec la fonction afficher_publications_hal().

Si le format JSON ne vous convient pas, plusieurs autres formats sont disponibles. C’est le paramètre wt de la requête qui permet de spécifier le format de sortie attendu. Celui-ci n’avait pas été renseigné dans la requête utilisée jusque là et avait donc gardé sa valeur par défaut.

Pour demander des résultats au format CSV :

ma_requete_csv = "http://api.archives-ouvertes.fr/search/CRLAO/?q=title_t:python&rows=3&sort=submittedDate_tdate desc&wt=csv"

Réponse obtenue :

docid,halId_s,version_i,docType_s,citationFull_s,citationRef_s
3523195,hal-03523195,1,OTHER,"Alexander Delaporte. Utiliser TinySegmenter avec Python. 2022, https://tekipaki.hypotheses.org/2015. ⟨hal-03523195⟩","2022, https://tekipaki.hypotheses.org/2015"
3523158,hal-03523158,1,OTHER,"Alexander Delaporte. Lire (et modifier) un fichier XML avec Python. 2021, https://tekipaki.hypotheses.org/1906. ⟨hal-03523158⟩","2021, https://tekipaki.hypotheses.org/1906"
3521321,hal-03521321,1,OTHER,"Alexander Delaporte. Navigation web automatique avec Python. 2021, https://tekipaki.hypotheses.org/1475. ⟨hal-03521321⟩","2021, https://tekipaki.hypotheses.org/1475"

Pour certains formats de réponse, notamment le JSON (défaut ou wt=json) et le XML (wt=xml), je vous conseille d’ajouter le paramètre indent=true. Son effet est, de façon assez transparente, d’indenter les données en réponse plutôt que de les retourner sur une seule (longue) ligne. C’est appréciable pour visualiser la réponse directement dans la console (avec print(), comme dans le script mis à disposition) mais il est aussi intéressant d’utiliser ce paramètre lorsqu’on souhaite sauvegarder les résultats dans un fichier, puisque l’indentation est alors conservée.

Résultats enregistrés dans un fichier XML sans indent=true :

Résultats enregistrés dans un fichier XML avec indent=true :

Voici le fonctionnement général de l’interrogation de l’API HAL avec Python et la librairie requests à travers un exemple simple. Ceci peut constituer un point de départ en vue de la construction de requêtes plus complexes et précises, avec l’aide de la documentation de l’API, qui est claire et complète.

Citer ce billet : “Interroger l’API HAL avec Python”, par Alexander Delaporte. Publié sur Tekipaki le 13/01/2022. Lien : https://tekipaki.hypotheses.org/2102.
  1. Ce qui est peu probable, puisque le CRLAO (Centre de recherches linguistiques sur l’Asie orientale) ne se spécialise absolument pas dans l’informatique. []
  2. Que ces champs soient disponibles dans le formulaire ne signifie pas qu’ils soient applicables à toute publication, si on restreint la requête à un champ particulier il faut d’abord s’assurer de sa pertinence. []
  3. D’après la documentation : Le tri des résultats peut se faire sur n’importe quel champ en évitant les champs de type text (suffixe "_t") et les champs multi-valués qui donneront des résultats imprévisibles. []
  4. ma_requete = "http://api.archives-ouvertes.fr/search/CRLAO/?q=title_t:python&rows=3&sort=submittedDate_tdate desc" []

Auteur/autrice : Alexander Delaporte

Ingénieur d'études au Centre de recherches linguistiques sur l'Asie Orientale

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.