2 Internet, manipuler des URLs

Il peut être intéressant d’obtenir le numéro WOS d’un article scientifique. Ce numéro est cependant fastidieux à obtenir, d’autant plus si nous souhaitons le récupérer pour une liste d’articles ! Par chance The Kitchin Research Group dans leur blog de juin 2015 (http://kitchingroup.cheme.cmu.edu/blog/2015/06/08/Getting-a-WOS-Accession-number-from-a-DOI/) propose une méthode pour récupérer le numéro WOS à partir du numéro DOI. C’est cette méthode que nous allons utiliser avec R et le package httr. En bref, cette méthode consite à interroger le site web du WOS à partir du numéro DOI. Le site web du WOS va répondre en spécifiant qu’il faut se connecter pour accéder à l’article. Il y a pour cela une redirection vers une page web dont l’URL contient le numéro WOS. Il suffit alors d’extraire le numéro WOS de l’URL de la page web. Si nous utilisons un proxy pour accéder au site web du WOS, il faut donc le désactiver pour que la méthode fonctionne.

Tout d’abord si cela n’est pas déjà fait il faut installer le package httr avec install.packages("httr"), puis le charger avec library("httr"). Une autre solution consiste à utiliser la fonction suivante qui va vérifier si le package est installé puis le charger (il existe de nombreuses déclinaisons de cette fonction sur internet, il s’agit ici d’un mélange de multiples sources).

pkgCheck <- function(packages){
  for(x in packages){
    try(if (!require(x, character.only = TRUE)){
      install.packages(x, dependencies = TRUE)
      if(!require(x, character.only = TRUE)) {
        stop()
      }
    })
  }
}
pkgCheck("httr")

La liste des numéros DOI est la suivante (contenu dans un vector) :

myDOIs <- c(
  "10.1111/2041-210X.12935", 
  "10.1007/s13355-017-0480-5")
print(myDOIs)
## [1] "10.1111/2041-210X.12935"   "10.1007/s13355-017-0480-5"

Pour chaque DOI, nous allons interroger le site web du WOS, récupérer l’URL de redirection, puis récupérer le numéro WOS. Nous allons donc faire une boucle sur notre vector contenant les DOI. Nous utilisons la fonction seq_along() qui va prendre comme valeurs les éléments d’une séquence de 1 à la taille de l’objet myDOIs, soit : i = 1, puis i = 2.

for(i in seq_along(myDOIs)){
  # ...
}

Dans la boucle, le DOI que nous allons traiter est donc myDOIs[i] que nous allons appeler myDOI. La page d’interrogation du WOS correspond à la concaténation de l’URL du WOS avec le numéro WOS (l’URL est présentée sur plusieurs lignes pour respecter la largeur de page de ce livre).

for(i in seq_along(myDOIs)){
  myDOI <- myDOIs[i]
  myWebPage <- paste0(
    "http://ws.isiknowledge.com/", 
    "cps/openurl/service?url_ver=Z39.88-2004", 
    "&rft_id=info:doi/", myDOI)
}

Maintenant nous allons utiliser la fonction GET() du package httr pour récupérer l’URL.

for(i in seq_along(myDOIs)){
  myDOI <- myDOIs[i]
  myWebPage <- paste0(
    "http://ws.isiknowledge.com/", 
    "cps/openurl/service?url_ver=Z39.88-2004", 
    "&rft_id=info:doi/", myDOI)
  r <- GET(myWebPage)
  urlWOS <- r[[1]]
}

Il se peut que pour un article, il n’y ait pas de numéro WOS correspondant. Pour que notre script ne soit pas arrêté en cas d’erreur il faut donc gérer cette exception. Nous allons créer un objet tryExtract qui va prendre comme valeur une chaîne de caractères vide "". Ensuite nous allons essayer avec la fonction try() d’extraire le numéro WOS avec la fonction substr(). Le numéro WOS se situe depuis le caractère numéro 117 jusqu’au caractère numéro 131 de l’URL.

for(i in seq_along(myDOIs)){
  myDOI <- myDOIs[i]
  myWebPage <- paste0(
    "http://ws.isiknowledge.com/", 
    "cps/openurl/service?url_ver=Z39.88-2004", 
    "&rft_id=info:doi/", myDOI)
  r <- GET(myWebPage)
  urlWOS <- r[[1]]
  tryExtract <- ""
  try(
    tryExtract <- substr(
      x = urlWOS, 
      start = 117, 
      stop = 131), 
    silent = TRUE)
}

Nous pouvons ensuite vérifier que l’extraction correspond bien à un numéro en utilisant une expression régulière. Ici nous allons simplement vérifier que l’extraction ne contient que des chiffres. Dans le cas contraire tryExtract reprendra sa valeur initiale "".

for(i in seq_along(myDOIs)){
  myDOI <- myDOIs[i]
  myWebPage <- paste0(
    "http://ws.isiknowledge.com/", 
    "cps/openurl/service?url_ver=Z39.88-2004", 
    "&rft_id=info:doi/", myDOI)
  r <- GET(myWebPage)
  urlWOS <- r[[1]]
  tryExtract <- ""
  try(
    tryExtract <- substr(
      x = urlWOS, 
      start = 117, 
      stop = 131), 
    silent = TRUE)
  if(!grepl(
    pattern = '^[0-9]*$', 
    x = tryExtract)
  ){
    tryExtract <- ""
  }
}

Le résultat est ensuite stocké dans un vector créé au préalable et appelé vecWOS.

vecWOS <- vector()
for(i in seq_along(myDOIs)){
  myDOI <- myDOIs[i]
  myWebPage <- paste0(
    "http://ws.isiknowledge.com/", 
    "cps/openurl/service?url_ver=Z39.88-2004", 
    "&rft_id=info:doi/", myDOI)
  r <- GET(myWebPage)
  urlWOS <- r[[1]]
  tryExtract <- ""
  try(
    tryExtract <- substr(
      x = urlWOS, 
      start = 117, 
      stop = 131), 
    silent = TRUE)
  if(!grepl(
    pattern = '^[0-9]*$', 
    x = tryExtract)
  ){
    tryExtract <- ""
  }
  vecWOS <- append(vecWOS, tryExtract)
}

Nous pouvons alors créer un objet de type data.frame qui va contenir les numéros DOI et les numéros WOS, et éventuellement l’exporter dans un fichier CSV.

dfDOIWOS <- data.frame(
  DOI = myDOIs, 
  WOS = vecWOS)
write.csv(
  dfDOIWOS, 
  file = "dfDOIWOS.csv", 
  row.names = FALSE)

Le résultat est le suivant (non exécuté car la procédure d’interrogation avec la fonction GET() est très lente : si nous souhaitons travailler sur un liste de plusieurs dizaines ou centaines d’articles, plusieurs heures seront nécessaires avant d’obtenir le résultat).

#                         DOI             WOS
# 1   10.1111/2041-210X.12935 000429421800031
# 2 10.1007/s13355-017-0480-5 000400381400016

Voici le code complet :

pkgCheck <- function(packages){
  for(x in packages){
    try(if (!require(x, character.only = TRUE)){
      install.packages(x, dependencies = TRUE)
      if(!require(x, character.only = TRUE)) {
        stop()
      }
    })
  }
}
pkgCheck("httr")

myDOIs <- c(
  "10.1111/2041-210X.12935", 
  "10.1007/s13355-017-0480-5")

vecWOS <- vector()
for(i in seq_along(myDOIs)){
  myDOI <- myDOIs[i]
  myWebPage <- paste0(
    "http://ws.isiknowledge.com/", 
    "cps/openurl/service?url_ver=Z39.88-2004", 
    "&rft_id=info:doi/", myDOI)
  r <- GET(myWebPage)
  urlWOS <- r[[1]]
  tryExtract <- ""
  try(
    tryExtract <- substr(
      x = urlWOS, 
      start = 117, 
      stop = 131), 
    silent = TRUE)
  if(!grepl(
    pattern = '^[0-9]*$', 
    x = tryExtract)
  ){
    tryExtract <- ""
  }
  vecWOS <- append(vecWOS, tryExtract)
}

dfDOIWOS <- data.frame(DOI = myDOIs, WOS = vecWOS)
write.csv(
  dfDOIWOS, 
  file = "dfDOIWOS.csv", 
  row.names = FALSE)

La boucle for() pourrait être remplacée par une boucle sapply() pour gagner en temps d’exécution. Un gain serait également possible en effectuant une parallélisation sur cette boucle. Pour information, voici un exemple de temps d’exécution renvoyé par la fonction system.time() et microbenchmark::microbenchmark() :

# system.time()
#   user  system elapsed
#   0.10    0.01   35.00

# microbenchmark()
# Unit: seconds
#     expr    min     lq    mean median     uq    max neval
#  myFun() 36.589 36.589 36.589  36.589 36.589 36.589     1

Nous venons de faire un script qui permet à partir d’une liste de numéros DOI d’obtenir automatiquement les numéros WOS.