Ét.Nadji.fr/

Du code, des mots, des livres.

Interroger IdRef avec Python

13/04/2018 à 19h
Remarque:
Ce billet présente le principe général de l’interrogation d’IdRef en Python, et non une solution complète à la récupération de toutes les informations d’une notice d’autorité. Il est possible de récupérer les identifiants HAL, ORCID d’un auteur sans problèmes avec ElementTree, mais je n’en parlerais pas ici. De même, je ne vais pas expliquer comment passer d’une requête à des centaines : si vous connaissez la programmation, ça ne devrait pas poser le moindre problème.

Dans le cadre de mon travail aux Presses universitaires de Strasbourg, je dois parfois retrouver l’identité et les coordonnées de chercheurs (typiquement, leur affiliation à tel ou tel établissement universitaire).

Il y a bien des façons de les retrouver. La requête Google fonctionne assez bien, mais tout le monde n’a pas de page dediée sur le site de leur université. Pour les auteurs français, une requête IdRef évite de faire le tri des résultats Google, et surtout, traite bien mieux les homonymes1.

Mais bon, quitte à retrouver des notices d’autorités, autant les retrouver toutes d’un coup en programmant (fort peu) avec Python. On pourrait transposer à PHP, et d’autres langages avec une librairie traitant les requêtes HTTP et les documents XML.

Mise à jour (février 2019)

IdRef a rendu publique sa base de triplets, pour ceux que RDF et les requêtes SPARQL intéressent.

Sommaire

  1. Solr
  2. La notice XML de l’universitaire
  3. (Non)-profit !

Étape 1 : Solr

La première étape pour interroger IdRef… c’est d’avoir une requête, et une requête valide. IdRef emploie le moteur de recherche Apache Solr, qui a l’avantage de retourner ses résultats en divers formats, dont JSON et Python.

Pour créer la requête, il nous faut un exemple d’URL, comme celui-ci:

https://www.idref.fr/Sru/Solr?q=persname_t:(VAR_NOM AND VAR_PRENOM)&wt=python

Il se présente cependant une petite difficulté, à savoir l’encodage de certains caractères. Il faut employer l’encodage « avec des pourcents » sur les parties susceptibles d’avoir des espaces, des accents et autres joyeusetés non-ASCII.

Cela se fait aisément avec urllib.parse.quote :

from urllib.parse import quote
# Retourne '%20AND%20' ... quote(" AND ")

On peut donc créer une fonction pour produire l’URL d’une requête par nom et prénom (facultatif):

def get_url(nom, prenom=False):
    if prenom:
        req = quote("{} AND {}".format(nom, prenom))
    else:
        req = quote(nom)
    
    url = "https://www.idref.fr/Sru/Solr?q=persname_t:({})&wt=python".format(req)
    
    return url

Après quoi on récupère les données:

from urllib.request import urlopen

donnees = urlopen(url).read()

Puisque Solr le permet, les données sont renvoyées sous forme de texte préparé pour Python. Il faut transformer ces données en objets Python, et c’est assez simple :

donnees = eval(donnees)

La majorité des données retournées est sans grand intérêt, et on se contente de récupérer les PPN — les identifiants uniques d’IdRef et du SUDOC. Il peut y avoir plusieurs résultats, donc on récupère une liste de PPN.

ppns = [person["ppn_z"] for person in donnees["response"]["docs"]]

Étape 2 : La notice XML de l’universitaire

Puisqu’on a le PPN de l’auteur, on peut à présent récupérer facilement sa notice XML sur IdRef et le SUDOC :

https://www.idref.fr/ID_AUTEUR.xml
http://www.sudoc.abes.fr//DB=2.1/SET=2/TTL=1/REL?PPN=ID_AUTEUR

On récupère le contenu de la notice avec urlopen et on l’analyse avec ElementTree :

import xml.etree.ElementTree as ET

scholars = []

def get_value(info):
    if info.tag == "subfield":
        if "code" in info.attrib and info.attrib["code"] == "a":
            return info.text.strip()
            
    return False

for ppn in ppns:
    xml = urlopen("https://www.idref.fr/{}.xml".format(ppn)).read()
    root = ET.fromstring(xml)
    
    if root:
        scholars.append({"ppn":ppn})
    
        for datafield in root:
            if datafield.tag == "datafield" and "tag" in datafield.attrib:
                info_type = datafield.attrib["tag"]
                
                if info_type == "900":
                    for sub_info in datafield:
                        value = get_value(sub_info)
                        if value:
                            scholars[-1]["name"] = value
                
                if info_type in ["300","340"]:
                    for sub_info in datafield:
                        value = get_value(sub_info)
                        if value:
                            scholars[-1]["status"] = value

Étape 3 : (Non)-profit !

Quand à savoir si ces informations sont effectivement à jour, c’est une autre histoire2. En histoire comme ailleurs, la programmation et les meilleurs outils du monde ne dispensent pas de rester critique des données3

Notes

  1. Il y a, par exemple, 419 Jean Martin.
  2. Cité seulement pour l’expression, et parce que c’est une bonne chaîne. Mais bon, ça fait un moment que tout le monde la connaît maintenant.
  3. Bon, j’avoue ce paragraphe, c’était juste pour conclure le billet autrement qu’en queue de poisson.

Commentaires

Pour commenter ce billet, envoyez un mail sur etnadji (at) eml.cc, ou créez-vous votre blog.