Aller au contenu principal

Capturer les données d’écran d’un opac

07/03/2011

À part nos amis québécois, personne ne devrait avoir compris ce titre, mais si j’en crois Wikipédia, la capture de données d’écran est le terme préconisé par l’Office québécois de la langue française pour parler du sujet d’aujourd’hui.Mais pour me faire comprendre (encore que …), j’utiliserai plus volontiers le terme anglais de screen scraping, autrement dit les méthodes qui vont nous permettre d’extraire de l’information depuis une page web, en analysant ce qui nous est présenté à l’écran (plutôt dans le code source de la page pour être précis).

Je n’avais pas prévu de détailler ce principe, mais comme on me l’a demandé suite aux deux billets sur la dissémination de la bibliothèque avec Chrome, voici un billet bonus à cette mini-série. Les deux premiers épisodes étaient déjà un peu techniques, celui ci risque de l’être un peu plus, n’hésitez donc pas à passer votre chemin si le code ne vous intéresse pas.

Pourquoi ?

Dans un monde idéal, quelqu’un qui souhaiterait développer une application externe à partir de nos données, et qui pour ça voudrait connaître le nombre de résultats à une requête, interrogerait une page dédiée du type : nb_res.php?q=ma_recherche, et en retour le catalogue renverrait ce nombre sous une forme simple (pour schématiser). C’est ce genre de services que l’on ait en droit d’attendre quand on demande à ce que nos catalogues proposent des web services.

Malheureusement, rares sont les catalogues à proposer ce genre de fonctionnalités, alors le plus souvent, on va devoir simuler une consultation du catalogue et analyser la page de résultats pour en extraire ce qui nous intéresse.

Donc si vous voulez adapter à votre opac l’extension Chrome développée pour le Sudoc, il faudra essentiellement adapter le script chargé d’interroger le Sudoc (en lui envoyant la requête que l’internaute a lancé sur Google) et d’en extraire le nombre de résultats pour cette requêtes, afin qu’il interroge votre catalogue (URL de requête différente) pour en extraire le nombre de résultats (présente dans un endroit de la page de résultats générée).

Donc il faut comprendre le script actuel.

Les limites

Ces méthodes sont très dépendantes de la manière dont l’opac présente les données. Si l’on souhaite connaître le nombre de résultats et qu’à un instant t, la page de résultats indique « Votre recherche a retourné 158 réponses », on va extraire ce qui se trouve entre retourné et réponses. Mais si demain l’administrateur change son affichage et le modifie par « 158 résultats à votre recherche », notre script ne fonctionnera plus !

Schéma des flux dans l'extension

Alternative avec un script intermédiaire

Si la fonction d’analyse est effectuée au niveau d’une extension Chrome ou d’un script Greasemonkey, s’il y a un changement sur l’opac cible, on devra mettre à jour l’extension et la distribuer à tous les usagers, opération qui peut être compliquée (dans le cas des scripts Greasemonkey par exemple). De plus, il n’est pas toujours évident d’analyser le contenu d’une page, alors si à partir des informations, on veut faire une extension Chrome, un script Greasemonkey et une application Facebook, il faudra sur chacune de ces plateformes reproduire l’analyse des pages du catalogue.

Une solution pour éviter ces désagréments est d’avoir un script sur un serveur intermédiaire qui va se charger de faire cette analyse et ne renvoyer que l’information de base. Dans le schéma ci-dessus, si le Sudoc modifie la manière dont sont présentés les résultats, on corrigera simplement le script nb_res_sudoc.php. Comme les extensions installées chez les usagers ne font pas de requêtes directement sur le Sudoc mais passent par le script nb_res_sudoc.php, elles fonctionneront à nouveau.

Nombre de résultats du Sudoc

Pour illustrer le propos, nous allons détailler pas à pas ce script nb_res_sudoc.php dont le but est de retourner pour une requête donnée, le nombre de résultats dans le Sudoc (résultat pour la requête Talence). Ce script a été développé en php, un langage serveur très répandu, mais le principe peut facilement être décliné sur d’autres langages.

Récupérer la requête

if (!isset($_GET['q']))
{
  print "Manque la requête en paramètre";
  exit;
}
$q = str_replace(" ", "+", $q);

Dans un premier temps, on commence par récupérer la requête passée par le paramètre q. Puis, à la ligne 6 on va remplacer tous les espaces par le signe +, utilisé dans le Sudoc pour séparer les mots de la requête.

Récupérer la page de résultats

// On récupère la page correspondant au résultat de cette requête
$url  = "http://www.sudoc.abes.fr/DB=2.1/CMD?ACT=SRCHA&IKT=1016&SRT=RLV&TRM=".$q;

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$res = curl_exec($ch);

Ensuite, on construit l’url d’interrogation, dans laquelle le paramètre IKT correspond à l’index qu’on utilise, ici 1016 pour Tous les mots. Puis on place la requête dans le paramètre TRM qui correspond au terme d’interrogation.

Ensuite, on va récupérer le contenu de la page qui se trouve à cette adresse. On utilise pour cela la librairie cURL, un peu plus compliquée que la fonction PHP de base dédiée à cette opération (file_get_contents) mais qui a l’avantage de disposer de nombreux paramètres. Pour nos catalogues qui sont friands de formulaires, cookies, redirections et autres, on est parfois obligé de passer par les options de cette librairie pour arriver à récupérer le contenu qui nous intéresse.

Ici, on ne va utiliser que quelques options :

  • CURLOPT_URL : l’url que l’on souhaite télécharger
  • CURLOPT_RETURNTRANSFER : permet, lors de l’utilisation de la fonction curl_exec de récupérer la page disponible à l’url ci-dessus dans une variable. Si cette option n’est pas activée, le contenu de la page appelée sera directement affiché à l’écran et l’on n’aura pas de possibilité d’analyser le code source comme nous souhaitons le faire.
  • CURLOPT_FOLLOWLOCATION : la première page affichée par le Sudoc n’est pas celle qui contient les résultats. Une redirection est effectuée sur le serveur de l’abes, cette option nous permet de suivre cette redirection et d’aboutir sur la page contenant réellement les résultats.

Finalement, on récupère dans $res le code_source de la page de résultats.

Parmi les options dont on n’a pas besoin ici mais qui dans nos catalogues peuvent être utiles, il en existe qui permettent de passer de page en page un cookie pour maintenir des informations de session, parfois obligatoires.

Extraire le nombre de résultats

$tab_sortie = Array();

if (preg_match('/<span>([0-9]*)\x{C2}\x{A0}résultat/', $res, $match))
{
 $tab_sortie["nb"] = $match[1];
}
else
{
 $tab_sortie["nb"] = 0;
}

Dans cette section, on va aller chercher dans la page l’endroit où le nombre de résultats est indiqué. Si l’on regarde le code source généré il est de la forme :

<span>3677&nbsp;résultat(s)

L’extraction se passe à la ligne 3 avec la fonction preg_match qui va extraire du code source de la page le motif [0-9]*, qui signifie : un chiffre : [0-9], répété autant de fois que possible : *. Comme on a mis ce motif entre parenthèses, il sera isolé dans la variable passée en troisième argument de preg_match. Cette variable est un tableau qui va contenir dans sa première case la chaîne globale, puis dans chacune des cases suivantes les motifs isolés par les parenthèses, dans l’ordre où ils apparaissent. Pour le reste de l’expression régulière, on reproduit la chaîne telle qu’elle apparaît, si ce n’est qu’on remplace le &nbsp; (code HTML pour l’espace insécable) par sa valeur en unicode : \x{C2}\x{A0}.

Retourner le résultats

print json_encode($tab_sortie);

Finalement, on va afficher le contenu du tableau qu’on a constitué au format JSON (présentation détaillée sur wikipédia). Dans le cas qui nous intéresse ce format n’est pas forcément nécessaire, mais dès qu’on a plusieurs informations à retourner, il permet de les isoler facilement, et a l’avantage d’être facilement traitable en javascript.

En conclusion

L’extension, le script Greasemonkey ou la page Facebook pour laquelle on avait besoin de connaître le nombre résultats, pourra appeler directement cette page nb_res_sudoc.php et recevra un simple tableau, qui pour la clé ‘nb’ indique le nombre de résultats. On simplifie énormément le code au niveau du service que l’on va créé, et on peut facilement réutiliser ce script serveur pour plusieurs extensions.

J’ai utilisé ce principe pour pas mal de choses autour du Sudoc, par exemple pour récupérer la liste des bibliothèques possédant un document, à partir de son ppn.

J’espère qu’avec cet article le fonctionnement de ces scripts de screen scraping vous paraîtra plus clair. J’ai essayé de faire au plus clair avec ce cas concret du nombre de résultats à une requête, et si des choses restent floues, les commentaires sont à disposition !

8 commentaires
  1. 07/03/2011 11:06

    Merci ! Reste à tout comprendre, puis à l’utiliser. Mais c’est juste génial (j’en avais marre de m’entendre dire que c’est pas possible).

  2. 07/03/2011 14:56

    C’est pour ça qu’on laisse pas des ingénieurs tenir des blogs… je comprends autant qu’un billet du Figoblog 😀 😀 😉

    Par contre j’aimerais bien savoir comment tu ajoute des boutons en survol sur tes images de code? c’est bien pratique…

  3. 07/03/2011 15:24

    Mais je voulais pas poster des insanités de ce type, moi, on m’a demandé c’est pas de ma faute 🙂

    Mais pour répondre à ta vraie question c’est en utilisant la balise sourcecode :
    http://en.support.wordpress.com/code/posting-source-code/

  4. 14/03/2011 10:07

    Tiens c’est rigolo, j’avais fait ça pour récupérer les données de l’OPAC Millenium dans le feu portail Jouve du SCD de Valenciennes, justement… un chaos : sur l’OPAC, les balises HTML n’étaient pas fermées… et puis j’ai recommencé pour récupérer en PHP les données d’un viel OPAC Portfolio. C’était plus stable, et on pouvait ajouter des outils web 2.0 à un OPAC qui n’en avait pas.
    Après, je suis passé à Koha : connexion directe à la base MySQL 😉 et bientôt ILS-DI : http://old.diglib.org/architectures/ilsdi/

    Bref, super idée !
    Avec ça, on pourrait faire de l’envoi de notices via SMS ?

  5. 14/03/2011 10:56

    @hatt marrant que tu parles d’envoi de notices par sms, on m’a proposé de réfléchir à cela il y a peu.

    Ca me paraît envisageable en récupérant les données de l’opac bien évidemment, mais si on veut que l’usager puisse faire cela, il faut quand même qu’à un moment sur l’opac il ait un lien qui lui propose d’envoyer par sms la notice, donc avoir accès à la modification des ses templates.

    Reste le problème de l’envoi des sms en tant que tel, il y avait ce post sur Des bibliothèques 2.0 : http://bibliotheque20.wordpress.com/2008/10/14/envoi-automatique-de-sms-en-bibliotheque/ qui parlait de 10cts / sms, ça me paraît un peu cher, je ne sais pas si les prix ont évolué depuis.

Trackbacks

  1. Quai Branly, Primo et Zotero « Bibliothèques [reloaded]
  2. Ta BU dans Chrome (le kit Just Do It) « Bibliothèques [reloaded]
  3. Contrôle qualité de notices du Sudoc | aka Reup

Commentaires fermés