From 27d18a564adbaffa734a8c71890a24002931eb6c Mon Sep 17 00:00:00 2001 From: Rachid Aliouat <rachid.aliouat@univ-lille.fr> Date: Wed, 8 Feb 2023 17:47:36 +0100 Subject: [PATCH] ajout du programme recup-sets-alma.pl pour recuperer les resultats d un jeu de resultats --- gestion_des_sets/README | 14 ++ gestion_des_sets/config.exemple | 6 + gestion_des_sets/recup-sets-alma.pl | 251 ++++++++++++++++++++++++++++ 3 files changed, 271 insertions(+) create mode 100644 gestion_des_sets/README create mode 100644 gestion_des_sets/config.exemple create mode 100644 gestion_des_sets/recup-sets-alma.pl diff --git a/gestion_des_sets/README b/gestion_des_sets/README new file mode 100644 index 0000000..acf15fd --- /dev/null +++ b/gestion_des_sets/README @@ -0,0 +1,14 @@ +API Configuration and Administration + +programme recup-sets-alma.pl + +Programme qui va récuperer les membres d'un sets alma. C'est à dire les résultats de recherche d'une jeu de résultat Alma. +Api utilise : Retrieve Set Members +GET /almaws/v1/conf/sets/{set_id}/members + +fichier de conf à passer en parametre + + +perl recup-sets-alma.pl config-test.conf + +Le fichier de conf contient la cle api et le numéro de l'ensemble : set_id diff --git a/gestion_des_sets/config.exemple b/gestion_des_sets/config.exemple new file mode 100644 index 0000000..07ec343 --- /dev/null +++ b/gestion_des_sets/config.exemple @@ -0,0 +1,6 @@ +api_user_conf RecupConfSandBox +api_cle_conf l8xx403e####################bcf612 +set_id 123456891011213141516 +fic_sortie resultats.csv +horodatage no + diff --git a/gestion_des_sets/recup-sets-alma.pl b/gestion_des_sets/recup-sets-alma.pl new file mode 100644 index 0000000..e918e83 --- /dev/null +++ b/gestion_des_sets/recup-sets-alma.pl @@ -0,0 +1,251 @@ +#!/usr/bin/perl -w +################## +# Rachid Aliouat +# Le 07/02/2023 +# API Configuration and Administration +# Récupérer les résultats de recherche d'un jeu +################# +use strict; +use warnings; +use LWP::UserAgent; # bibliothèque pour les webservice +use XML::Twig; # bibliothèque pour le XML +use URI::Encode qw(uri_encode uri_decode);; #encoder decoder les URL - requiert la bibliotheque liburi-encode-perl + +my $token=""; +my @tab_resultats=(); +my @tab_ppn=(); +my $indice=0; +my $j=0; +my $nom_fic_conf=""; +my $nom_fic_csv=""; +my %hash_entete=(); # pour retrouver plus facilement une valeur +my @tab_entete=(); # pour parcourir dans l'ordre les colonnes +my $ligne_entete_csv=""; +my $nbr_colonne=0; +my $entete_csv_deja_ecrit=0; +my $taille_lot=100; # taille d'un lot de resultat i.e "la limite" +#my $max_ppn_url = 100; # nombre max de bloc ppn dans l'url : attention une url est limitée en nombre d'octect : pas plus de 100 PPN car c'est encapsulé dans des balises XML verbeuses... +#my $compteur_ppn=0; + +$nom_fic_conf=$ARGV[0]; + +##### LIRE LE FICHIER DE CONF +my %hash_conf=(); +open (CONF, $nom_fic_conf) or die "Ouverture fichier de configuration $nom_fic_conf impossible , cause : $! \n"; +print "lecture de la configuration:\n"; +print "-" x 20, "\n"; +my @tab_inter = <CONF>; +close(CONF); +my $i=0; +for ($i=0;$i<=$#tab_inter;$i++) { + print $tab_inter[$i]; + my @ligne=split('\t',$tab_inter[$i]); # decoupage ligne + $hash_conf{$ligne[0]}=epure($ligne[1]); # alimentation de la table de hash avec la conf + +} +print "-" x 20, "\n"; +##### si horodatage du nom de fichier est "yes" +if ($hash_conf{'horodatage'}=~ /yes/){ + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(); + #printf("%02d:%02d:%02d", $hour, $min, $sec); + #my $date_jour=sprintf("%02d-%02d-%04d", $mday, ($mon+1), (1900+$year)); + my $date_jour=sprintf("%04d-%02d-%02d", (1900+$year),($mon+1),$mday); + print "Horodatage : $date_jour\n"; + $hash_conf{'fic_sortie'}=$date_jour."-".$hash_conf{'fic_sortie'}; +} + +########### Appel de l'API Configuration + +my $twig_rapport=XML::Twig->new( # on créer un objet TWIG dans lequel on met toute la structure XML + + pretty_print => 'indented', +); + ## on commence par récuperer juste le 1er resultat pour analyse : liste des noms de colonne, nombre de resultats au total + my $block_xml=get_alma_sets_by_id($hash_conf{set_id},1,0); # Appel de l'API configuraiton sur l'id du set present dans le fichier de conf + $block_xml =~/<members total_record_count=\"(\d{1,})\">/; + my $nbr_membres =$1; + $twig_rapport->parse($block_xml); # ici tout est dans la structure twig + print $twig_rapport->sprint; # affichage du contenu + print "\n###########\nIl y a $nbr_membres resultats au total à récupérer\n"; + print "Liste des colonnes :\n"; + aliment_tab_indices ($twig_rapport); ### Alimentation de la ligne d'entete avec les intitulé de colonne pour le CSV + + ### On doit boucler pour récuperer tous les résultats car il n'y a pas de notion de ResumeToken + ### On va jouer avec les parametre limit(nombre de membre à renvoyer) offset (la notion de saut) + ### donc on recupére les 100 premiers, puis les 100 suivant en sautant de 100 positions + ### on commence par faire un calcul pour savoir combien d'appel on va faire + ### $nbr_appel = $nbr_membres / 100 ==> arrondi à l'entier supérieur + my $nbr_appel = div_entier_sup($nbr_membres,100); + print "pour $nbr_membres membres, il faut $nbr_appel appel(s)\n"; + + #### Appels api pour recuperer tous les résultats de recherche par paquet de 100 :limit=100 et offset=$nbr + #$i=1; + my $limit=$taille_lot; + my $offset=0; + for ($i=1;$i<=$nbr_appel;$i++) { + $offset=(($i-1)*$limit); + print "Appel API $i / $nbr_appel : limit=$limit offset=$offset\n"; + $block_xml=get_alma_sets_by_id($hash_conf{set_id},$limit,$offset); # Appel de l'API configuraiton sur l'id du set present dans le fichier de conf + $twig_rapport->parse($block_xml); + aliment_tab_resultats($twig_rapport); + + } + + +################ Fonctions + +########### fonction Retourne la chaine de caractère passée en paramètre en ne laissant que les caractères autorisés +sub epure { + my ($res)=@_; + + $res=~ s/\n//g; + $res=~ s/\r//g; + #$res=~ s/\"//g; + + return $res; +} + +#### Division en arrondissant à l'entier supérieur +sub div_entier_sup { + my ($num_1,$num_2)=@_; + + my $res = 0; + +if(($num_1 % $num_2) == 0){ + $res = $num_1 / $num_2; + } + else{ + $res = int($num_1 / $num_2) + 1; + } + return($res); +} + + +######## Fonction alimente tableau indice de colonne pour chaque libellé de colonne car l'ordre des colonnes peut changer si on modifie le rapport analytics + +sub aliment_tab_indices{ + my ($twig_rapport)=@_; + my $z=0; + my $nom_col=""; + my $numero_col=$z; + + my $root= $twig_rapport->get_xpath('//members',0); + #print $root->sprint; # affichage du contenu + print "\n"; + + my @les_colonnes= $root->first_child('member')->children; ### on récuperer une table de hash de tous les "enfants" du root + + foreach my $une_colonne (@les_colonnes) # liste chaque nouveaute de la liste des nouveautes + { + #print $une_colonne->name,"\n"; + $nom_col=$une_colonne->name; + $numero_col=$z; + print "Colonne num $numero_col -> $nom_col\n"; + $tab_entete[$numero_col]=$nom_col; + $hash_entete{$nom_col} = $numero_col; + $ligne_entete_csv.=$nom_col."\t"; + #$tab_entete[$z]=$nom_col; + $z++; + $nom_col=""; + } + $nbr_colonne=$z-1; + +} + + + +######## Fonction alimente tableau des resultats +sub aliment_tab_resultats{ + print "\nALIMENTE TABLE\n"; + my ($twig_rapport)=@_; + #print $twig_rapport->sprint; + my $root= $twig_rapport->get_xpath('//members',0); + #my $root= $twig_rapport->get_xpath('//',0); + + my @les_members= $root->children;#('members'); ### on récuperer une table de hash de tous les "enfants" du root = les entrées <Row> de la racine <rowset> + #print "#########################\n"; + #print "####".$root->first_child('Row')->first_child('Column12')->text()."####\n"; + my $i=0; + foreach my $un_member (@les_members) # liste chaque nouveaute de la liste des nouveautes + { + #print $un_member->sprint,"\n#######\n"; + for ($i=0;$i<=$#tab_entete;$i++) { + #print $tab_entete[$i]." : "; + #print $un_member->first_child($tab_entete[$i])->text(); + #print "\n"; + $tab_resultats[$indice][$i]=$un_member->first_child($tab_entete[$i])->text(); + } + + $indice++; + #print "\n"; + } + +} + + #### Ecriture du fichier CSV en mode Ajout +print "Ecriture du fichier CSV\n"; + open (FIC, ">".$hash_conf{fic_sortie}) or die "Ouverture fichier de liste exemplaire CSV impossible , cause : $! \n"; + binmode(FIC, ":utf8"); + +print FIC "$ligne_entete_csv\n"; +for ($i=0;$i<=$#tab_resultats;$i++) { + for ($j=0;$j<=$#tab_entete;$j++) { + print FIC $tab_resultats[$i][$j]; + if ($j<$#tab_entete) {print FIC "\t"} # on met une tabulation sauf après la derniere colonne + } + print FIC "\n"; +} + +close(FIC); + +############## fonction API GET pour questionner Alma API Configuration: Recuperer les données sur la base du set_id du jeu de resultat +sub get_alma_sets_by_id{ + + my ($set_id,$limit,$offset)=@_; # on récupére le set_id du jeu ou le offset en paramétre + print "Appel fonction GET\n ----\n$set_id\n$token\n"; + + print "$set_id\n"; + # Creer un agent pour questionner le webservice = céer un agent c'est comme ouvrir un navigateur internet + + my $ua = LWP::UserAgent->new; + $ua->agent("MyApp/0.1"); + # Creer la requete + my $chaine_rq=""; + + print "-----appel pour $limit resultats à partir de la position $offset----\n"; + $chaine_rq="https://api-eu.hosted.exlibrisgroup.com/almaws/v1/conf/sets/$set_id/members?limit=$limit&offset=$offset&apikey=".$hash_conf{api_cle_conf}; + print $chaine_rq,"\n"; + + my $req = HTTP::Request->new(GET => $chaine_rq); + $req->content_type('application/xml'); + $req->authorization_basic($hash_conf{api_user_conf}, $hash_conf{api_cle_conf}); # login + mot de passe => user_api + cle api + + # Passer requete au user agent et récuperer la reponse + my $i=0; + my $max=3; #maximum de tentative + my $status="NOK"; + while ($status =~ /^NOK$/){ + my $res = $ua->request($req); + # Vérifier la reponse + if ($res->is_success) { + print "##############################","\n"; + #print $res->content; + print "Existence notice OK pour $set_id\n"; + print "##############################","\n"; + $status=$res->content; + } else { + print $res->content; + print "\n############################","\n"; + print $res->status_line, "\n"; + print "\n############################","\n"; + $i++; + if ($i==$max) { + $status="MAX"; # on force la sortie de la boucle meme si c'est pas ok + } + } +} + + + return $status; +} + -- GitLab