Newer
Older
api-wos / SOAP / WosSearchByDoi.sh
@besagni besagni on 25 Jul 2022 9 KB Homogénéisation des options
#!/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/&lt;/</go; 
                $r =~ s/&gt;/>/go; 
                $r =~ s/&amp;(\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