#!/bin/bash # Initialisation des variables pour les options programme=$(basename $0) substitut=$(echo $programme | sed 's/./ /g') version='1.6.2' modif='25/07/2022' function usage { echo "Usage : $programme -s sid -d (fichier|-) -r (résultats|-) [ -f champs ]* " echo " $substitut [ -T taille ] [ -j cookie_jar ] [ -i ] " echo " $programme -h " } function aide { cat << EOT Usage ===== $programme -s sid -d (fichier|-) -r (résultats|-) [ -f champs ]* $substitut [ -T taille ] [ -j cookie_jar ] [ -i ] $programme -h Options principales =================== -d indique le nom du fichier avec la liste des DOIs à chercher. Si on a un tiret “-” en argument, la liste de DOIs est lue sur l’entrée standard -h affiche cette aide -r indique le nom du fichier résultat (pour la sortie standard, utiliser le tiret “-” comme argument de l’option) -s indique le jeton d’authentification “SID” obtenu avec le programme d‘authentification à l‘API WoS -T indique le nombre de notices à télécharger à chaque itération (100 par défaut) Autres options ============== -f limite les champs présents dans les notices téléchargées. Cette option est répétitive (par défaut, tous les champs sont présents) -i ajoute dans la réponse de l’API la liste des identifiants WoS des notices retournées à chaque itération -j indique le nom du fichier qui recevra les cookies (“cookies.txt” par défaut) N.B. : la variable d‘environnement WOS_DELAY permet de modifier le délai entre deux itérations (1 seconde par défaut). Sa valeur doit être un entier positif supérieur à 1, par ex. : “export WOS_DELAY=3” EOT exit 0 } function nettoie { if [[ -f search$$.xml ]] then rm -f search$$.xml fi if [[ -f tmpWos$$.xml ]] then rm -f tmpWos$$.xml fi } # Déclaration explicite du tableau “bases” declare -a champs # Options while getopts d:f:hij:r:s:T: i do case $i in d) dois=$OPTARG;; f) champs+=($OPTARG);; h) aide;; i) recid=1;; j) cookiejar=$OPTARG;; r) sortie=$OPTARG;; s) sid=$OPTARG;; T) taille=$OPTARG;; \?) echo >&2 usage >&2 exit 1;; esac done # Vérification des options if [[ -z $sid || -z $dois || -z $sortie ]] then echo "Erreur : option(s) manquante(s)" >&2 echo "" >&2 usage >&2 echo "" exit 2 fi if [[ $dois = '-' ]] then dois='/dev/fd/0' fi if [[ $sortie = '-' ]] then sortie='/dev/fd/1' fi if [[ -z $cookiejar ]] then cookiejar='cookies.txt' fi # Vérification de la présence des programmes # “curl” et “xmllint” for i in curl xmllint do prog=$(which $i 2> /dev/null) if [[ -z $prog ]] then echo "" >&2 echo "Erreur : programme “$i” introuvable. Vérifier \$PATH." >&2 echo "" >&2 exit 3 fi done # Génération d’une liste de champs en XML avec l’option “-f” # Valeurs possibles : # UID, pub_info, names, full_name, titles, contributor, language, doctypes, # conf_title, conf_date, conf_host, conf_locations, sponsors, keywords, # keywords_plus, abstract, addresses, organizations, reprint_contact, # email_addr, grant, fund_text, refs, address_spec, headings, subjects, # identifiers, page, book_chapters et ids declare -a xml3 if [[ ${#champs[@]} -gt 0 ]] then for item in ${champs[@]} do while [[ -n $item ]] do deb=${item%%,*} fin=${item#*,} xml3+=(" <fieldName>$deb</fieldName>") if [[ $deb = $fin ]] then item="" else item=$fin fi done done fi # Variables diverses out='WosApiOut.txt' err='WosApiErr.txt' rec=0 max=0 total=0 # fonction verifie function verifie { perl -ne 'if (/<records[^>]*>(.+)/) { $r = $1; $r =~ s|</records>.*||; $r =~ s/</</go; $r =~ s/>/>/go; $r =~ s/&(\w+;)/&$1/go; $r =~ s|</REC>|</REC>\n|go; $r =~ s|<REC |\n<REC |go; print "$r\n"}' $1 | egrep '^<REC ' > tmpWos$$.xml nr=$(cat tmpWos$$.xml | wc -l) (echo "<records>" ; cat tmpWos$$.xml; echo "</records>") | xmllint -format - > /dev/null 2>> $err rc=$? rm -f tmpWos$$.xml if [[ $rc -gt 0 ]] then echo "" echo "Erreur : la réponse de l‘API est incorrecte [code xmllint = $rc]" >&2 echo " $nr / $2 notices trouvées" nettoie exit 6 elif [[ $nr -lt $2 ]] then echo "" echo "Erreur : la réponse de l‘API est incomplète " >&2 echo " $nr / $2 notices trouvées" nettoie exit 6 fi } # Fonction de génération du fichier SOAP, d’interrogation # de l’API et de test de la réponse function requete { local ns='FullRecord' end=$(( $3 + $2 - 1 )) printf " -> %d - %d " $3 $end >&2 # Génération du fichier SOAP # 1) entête + requête cat << EOT > search$$.xml <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:woksearch="http://woksearch.v3.wokmws.thomsonreuters.com"> <soapenv:Header/> <soapenv:Body> <woksearch:search> <queryParameters> <databaseId>WOS</databaseId> <userQuery>DO=($1)</userQuery> EOT # 2) Nb de notices cat << EOT >> search$$.xml <queryLanguage>en</queryLanguage> </queryParameters> <retrieveParameters> <firstRecord>1</firstRecord> <count>100</count> EOT # 3) liste des champs affichés (option “-f”) if [[ ${#xml3[@]} -gt 0 ]] then ns='Fields' echo " <viewField>" >> search$$.xml echo " <collectionName>WOS</collectionName>" >> search$$.xml for i in "${xml3[@]}" do echo " <fieldName>$i</fieldName>" >> search$$.xml done echo " </viewField>" >> search$$.xml fi # 4) Affichage des identifiants de notices retournées if [[ $recid -gt 0 ]] then echo " <option>" >> search$$.xml echo " <key>RecordIDs</key>" >> search$$.xml echo " <value>On</value>" >> search$$.xml echo " </option>" >> search$$.xml fi # 5) fin des paramètres cat << EOT >> search$$.xml <option> <key>targetNamespace</key> <value>http://scientific.thomsonreuters.com/schema/wok5.4/public/$ns</value> </option> </retrieveParameters> </woksearch:search> </soapenv:Body> </soapenv:Envelope> EOT # Interrogation de l’API WoS curl -X POST -d @search$$.xml -b $cookiejar -c $cookiejar -v 'http://search.webofknowledge.com/esti/wokmws/ws/WokSearch?wsdl' \ -H "Cookie: SID=$sid" 2> $err | xmllint -format - > $out 2>> $err rc=$? rs=$(perl -e 'print [(stat($ARGV[0]))]->[7]' $out) if [[ $rc -gt 0 ]] then echo "" echo "Erreur : la réponse de l‘API est incorrecte [code xmllint = $rc]" >&2 echo "" nettoie exit 6 fi # Test de la réponse qid=$(perl -ne 'print "$1" if m|<queryId>(.+?)</queryId>|;' $out) if [[ -n $qid ]] then rec=$(perl -ne 'print "$1" if m|<recordsFound>(.+?)</recordsFound>|;' $out) top=$(perl -ne 'print "$1" if m|<recordsSearched>(.+?)</recordsSearched>|;' $out) if [[ $rec -gt 100 ]] then echo " " echo "Erreur : le nombre de réponses ($rec) est supérieur au maximum autorisé (100)" echo " " nettoie exit 7 fi if [[ $rs -gt 12000000 ]] then verifie "$out" "$rec" fi total=$(( $total + $rec )) cat $out >> $sortie else msg=$(perl -ne 'print "$1" if m|<faultstring>(.+?)</faultstring>|;' $out) if [[ -n $msg ]] then echo " " echo "Erreur : $msg " echo " " else echo " " echo "Erreur indéterminée. " echo "Voir fichier “$err”. " echo " " fi nettoie exit 5 fi printf " \r" >&2 } # Nettoyage en cas d’arrêt prématuré trap nettoie HUP INT QUIT TERM # Itéraion sur la liste des DOIs max=${taille:-100} delai=${WOS_DELAY:-1} nb=0 offset=1 # Vérification des variables “$max” et “$delai” if [[ $max -lt 1 ]] then echo "Erreur : le nombre de notices par itération doit être compris entre 1 et 100" >&2 exit 4 elif [[ $max -gt 100 ]] then echo "Erreur : le nombre de notices par itération ne peut dépasser 100" >&2 exit 4 fi if [[ $delai -lt 1 ]] then echo "Erreur : la variable \$WOS_DELAY ne peut pas valoir moins d‘une seconde" exit 4 fi SECONDS=0 while read x do nb=$(( $nb + 1 )) if [[ $nb -eq 1 ]] then liste="\"$x\"" else liste="$liste OR \"$x\"" fi if [[ $nb -eq $max ]] then requete "$liste" "$nb" "$offset" offset=$(( $offset + $nb )) liste="" nb=0 while [[ $SECONDS -lt $delai ]] do sleep 0.5 done SECONDS=0 fi done < $dois if [[ $nb -gt 0 ]] then requete "$liste" "$nb" "$offset" fi nettoie nb=$(( $offset + $nb - 1 )) printf " \r" >&2 (echo " " >&2 echo "Nombre de DOIs cherchés : $nb" >&2 echo "Nombre de notices trouvées : $total / $top notices") | perl -pe '1 while(s/(\d)(\d\d\d)\b/$1 $2/o);' >&2 exit 0