Newer
Older
api-wos / REST / rWosSearchByDoi.sh
@besagni besagni on 25 Jul 2022 9 KB Ajout du script rWosSearchByDoi.sh
#!/bin/bash


# Initialisation des variables pour les options
programme=$(basename $0)
substitut=$(echo $programme | sed 's/./ /g')
version='0.3.1'
modif='25/07/2022'

function usage
{
echo "Usage : $programme -d (fichier|-) -r (résultats|-) [ -f champs ]* "
echo "        $substitut [ -T taill ] [ -j cookie_jar ] [ -ix ] "
echo "        $programme -h "
}

function aide
{
cat << EOT

Usage
=====
    $programme -d (fichier|-) -r (résultats|-) [ -f champs ]* 
    $substitut [ -j cookie_jar ] [ -ix ]  
    $programme -h

Options 
=======
    -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
    -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) 
    -h  affiche cette aide
    -i  ajoute dans la réponse de l’API la liste des identifiants WoS des 
        notices retournées 
    -j  indique le nom du fichier qui recevra les cookies (“cookies.txt” 
    -r  indique le nom du fichier résultat (pour la sortie standard, utiliser
        le tiret “-” comme argument de l’option)
    -T  indique le nombre de DOI à chercher à chaque itération (90 par défaut, 
        avec un maximum de 100)
    -x  indique que les notices doivent être en XML au lieu de JSON, le format 
        par défaut

EOT

exit 0
}

# Déclaration explicite des tableaux “bases” et “champs”
declare -a champs

format='json'

# Options
while getopts d:f:hij:r:T:x i
    do
    case $i in
        d) dois=$OPTARG;;
        f) champs+=$OPTARG;;
        h) aide;;
        i) recid=1;;
        j) cookiejar=$OPTARG;;
        r) sortie=$OPTARG;;
        T) taille=$OPTARG;;
        x) format='xml';;
        \?) echo  >&2
            usage >&2
            exit 1;;
    esac
    done

# Vérification des options
if [[ -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'
elif [[ ! -f $dois ]]
then
    echo "Erreur : fichier \"$dois\" introuvable" >&2
    exit 3
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 “jq”
for i in curl jq 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

# Vérification de la variable '$WOS_DELAY'
if [[ -n $WOS_DELAY && ! $WOS_DELAY =~ ^[1-9][0-9]*$ ]]
then
    echo "Erreur : la valeur de la variable \$WOS_DELAY doit être un entier supérieur à 1" >&2
    exit 2
fi

# Définition des fichiers de sortie
out="WosApiOut.$format"
err='WosApiErr.txt'
url='https://wos-api.clarivate.com/api/wos'

# Initialisation de la clé
if [[ -z $key ]]
then
    read -t 60 -s -p "clé d‘authentification : " key
    echo
    if [ $? -gt 128 ]
    then
        echo "" >&2
        echo "Erreur : temps de réponse (60 s) dépassé " >&2
        exit 3
    fi
fi

# Gestion des autres options
if [[ ${#champs[@]} -gt 0 ]] 
then
    optionView='FS'
    viewField='WOS'
    for item in ${champs[@]}
    do
        while [[ -n $item ]]
        do
            deb=${item%%,*}
            fin=${item#*,}
            viewField="$viewField+$deb"
            if [[ $deb = $fin ]]
            then
                item=""
            else
                item=$fin
            fi
        done
    done
    extra="\"optionView\": \"FS\", \"viewField\": \"$viewField\""
else
    extra="\"optionView\": \"FR\""
fi 

if [[ $recid -gt 0 ]] 
then
    extra="$extra, \"optionOther\": \"RI+On\""
fi

function requete
{
end=$(( $3 + $2 - 1 ))
printf " ->  %d - %d  " $3 $end >&2

cat << EOT > tee search.json 
{
  "databaseId": "WOS",
  "lang": "en",
  "usrQuery": "$1",
  "count": 100,
  "firstRecord": 1,
  $extra
}
EOT

if [[ $format = 'json' ]]
then
    curl -X POST -d @search.json -b $cookiejar -c $cookiejar -v "$url" \
         -H "Content-Type: application/json" \
         -H "X-ApiKey: $key" 2> $err | jq . 2>> $err > $out

    cr=$?
    echo "Code retour “jq” = $cr" >> $err

    if [[  $cr -gt 0 ]]
    then
        echo ""
        echo "Erreur : la réponse de l‘API est incorrecte [code jq = $cr]" >&2
        echo ""
    # nettoie
        exit 6
    fi

    # Test de la réponse
    msg=$(perl -ne 'print "$1" if /"message": "(.+?)"/o' $out)
    if [[ -n $msg ]]
    then
        cod=$(perl -ne 'print "$1" if /"code": "(.+?)"/o' $out)
        if [[ -n $cod ]]
        then
            msg="$cod: $msg"
        fi

        echo " "
        echo "Erreur : “$msg” "
        echo " "
        # nettoie
        exit 5

    else
        qid=$(perl -ne 'print "$1" if /^ +"QueryID": (\d+)/o;' $out)
        if [[ -n $qid ]]
        then
            rec=$(perl -ne 'print "$1" if /^ +"RecordsFound": (\d+)/o;;' $out)
            top=$(perl -ne 'print "$1" if /^ +"RecordsSearched": (\d+)/o;;' $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

            total=$(( $total + $rec ))
            cat $out >> $sortie
        fi

    fi

elif [[ $format = 'xml' ]]
then
    curl -X POST -d @search.json -b $cookiejar -c $cookiejar -v "$url" \
         -H "Content-Type: application/json" \
         -H "Accept: application/xml" \
         -H "X-ApiKey: $key" 2> $err | xmllint -format - 2>> $err > $out

    cr=$?
    echo "Code retour “xmllint” = $cr" >> $err

    if [[  $cr -gt 0 ]]
    then
        echo ""
        echo "Erreur : la réponse de l‘API est incorrecte [code xmllint = $cr]" >&2
        echo ""
        nettoie
        exit 6
    fi

    # Test de la réponse
    msg=$(perl -ne 'chomp; $l .= $_;}{print "$1" if $l =~ m|<message>(.+?)</message>|;' $out)
    if [[ -n $msg ]]
    then
        code=$(perl -ne 'chomp; $l .= $_;}{print "$1" if $l =~ m|<code>(.+?)</code>|;' $out)
        if [[ -n $code ]]
        then
            msg="$code: $msg"
        fi

        echo " "
        echo "Erreur : “$msg” "
        echo " "
        nettoie
        exit 5

    else
        qid=$(perl -ne 'print "$1" if m|<val name="QueryID">(\d+)</val>|;' $out)
        if [[ -n $qid ]]
        then
            rec=$(perl -ne 'print "$1" if m|<val name="RecordsFound">(\d+)</val>|;' $out)
            top=$(perl -ne 'print "$1" if m|<val name="RecordsSearched">(\d+)</val>|;' $out)

            cat $out >> $sortie
        fi
    fi

fi

printf "                                                \r" >&2
}

# Itéraion sur la liste des DOIs
max=${taille:-90}
delai=${WOS_DELAY:-1}
nb=0
offset=1
total=0

# 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 "DO=($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 "DO=($liste)" "$nb" "$offset"
fi

nb=$(( $offset + $nb - 1 ))

if [[ $format = 'json' ]]
then
    perl -ne 'if (not $m) {
                    if (/^( +)\{/o) {
                        $m = $1; 
                        if ($ok) {
                            print ","; 
                            $ok = 0;
                            } 
                        print;
                        }
                    } 
            else  {
                    if (/^$m/o) {
                        print; 
                        $n ++;
                        } 
                    else {
                        $ok ++ if $n; 
                        $m = "" if /^\{/o;
                        }
                    }' $sortie |
        (echo '{"Records": {"records": {"REC": ['; cat; echo ']}}}') |
            jq . > tmpWos$$.json

    mv tmpWos$$.json $sortie
#   offset=$(perl -ne '$nb ++ if /"UID": /o;}{print $nb;' $sortie)
else
    perl -ne 'foreach $rec (m|(<REC .+?</REC>)|go) {
                print "$rec\n";
                }' $sortie |
        (echo '<records>'; cat; echo '</records>') |
        xmllint -format - > tmpWos$$.xml

    mv tmpWos$$.xml $sortie
#   offset=$(perl -ne 'foreach $r (m|(<REC )|go) {$nb ++;}}{print $nb;' $sortie)
fi

amt=$(perl -ne 'print "$1" if /\bx-rec-amtperyear-remaining: (\d+)/o;' $err)

printf "                                                \r" >&2
echo " " >&2
echo "Nombre de DOIs cherchés : $nb" >&2
(echo "Nombre de notices trouvées : $total / $top notices"
 echo "Forfait restant : $amt" ) |
    perl -pe '1 while(s/(\d)(\d\d\d)\b/$1 $2/o);' >&2


exit 0