Newer
Older
api-wos / REST / rWosQuery.sh
@besagni besagni on 22 Jul 2022 12 KB Mise à jour de la doc
#!/bin/bash


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

function usage
{
echo "Usage : $programme -q 'requête' [ -r (résultats|-) ] [ -n nb_notices ] "
echo "        $substitut [ -[cmp] début:fin ] [ -l [0-9]+[DWMY] ] [ -b [WOS:]base ]* "
echo "        $substitut [ -f champs ]* [ -t CH:(A|D)[,CH:(A|D)]* ] "
echo "        $substitut [ -j cookie_jar ] [ -ix ] "
echo "        $programme -h "
}


function aide
{
cat << EOT

Usage
=====
    $programme -q 'requête' [ -r (résultats|-) ] [ -n nb_notices ]
    $substitut [ -[cmp] début:fin ] [ -l [0-9]+[DWMY] ] [ -b [WOS:]base ]*
    $substitut [ -f champs ]* [ -t CH:(A|D)[,CH:(A|D)]* ]
    $substitut [ -j cookie_jar ] [ -ix ]
    $programme -h

Options principales
===================
    -c  limite la recherche dans la base de données aux dates de création 
        des notices indiquées sous la forme aaaa-mm-jj:aaaa-mm-jj (comme par 
        exemple, “2000-01-01:2020-07-31”)
    -h  affiche cette aide
    -l  limite la recherche dans la base de données aux dates de chargement 
        des notices indiquées sous la forme d’un nombre de jours (D), de 
        semaines (W), de mois (M) ou d’années (Y). Les valeurs acceptées vont 
        de “0D” à “6D”, de “1W” à “52W”, de “1M” à “12M” et de “0Y” à “10Y” 
    -m  limite la recherche dans la base de données aux dates de modification 
        des notices indiquées sous la forme aaaa-mm-jj:aaaa-mm-jj (comme par 
        exemple, “2000-01-01:2020-07-31”)
    -p  limite la recherche dans la base de données aux dates de publication 
        indiquées sous la forme aaaa-mm-jj:aaaa-mm-jj (comme par exemple, 
        “2000-01-01:2020-07-31”)
    -r  indique le nom du fichier où placer les notices téléchargées (mettre
        un tiret pour indiquer la sortie standard)
    -q  fournit la requête à envoyer (entre simples ou doubles quotes si
        elle contient des espaces ou des caractères spéciaux)
    -x  indique que les notices doivent être en XML au lieu de JSON, le format 
        par défaut

Autres options
==============
    -b  limite la recherche à une ou plusieurs bases (e.g. “WOS:SCI”).
        Cette option est répétitive et “WOS:” est facultatif (par défaut,
        la recherche se fait sur l’ensemble du WoS)
    -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 (5 par défaut ou valeur de l’option “-n”)
    -j  indique le nom du fichier qui recevra les cookies (“cookies.txt”
        par défaut)
    -n  indique le nombre de notices, entre 0 et 100, à retourner (5 par
        défaut)
    -t  trie les résultats sur un champ (nom abrégé à 2 majuscules) de
        façon croissante (A) ou décroissante (D) ou par pertinence (RS)
        forcément décroissante

N.B. : on ne peut utiliser au maximum qu’une seule des options “-c”, “-l”, 
       “-m” ou “-p” à la fois, sinon cela entraîne une erreur.
 
EOT

exit 0
}

function nettoie
{
if [[ -f search$$.json ]]
then
    rm -f search$$.json
fi
}

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

format='json'

# Options
while getopts b:c:f:hij:l:m:n:p:q:r:t:x i
    do
    case $i in
        b) bases+=($OPTARG);;
        c) cdate=$OPTARG;;
        f) champs+=($OPTARG);;
        h) aide;;
        i) recid=1;;
        j) cookiejar=$OPTARG;;
        l) ldate=$OPTARG;;
        m) mdate=$OPTARG;;
        n) nrec=$OPTARG;;
        p) pdate=$OPTARG;;
        q) query=$OPTARG;;
        r) sortie=$OPTARG;;
        t) tri+=($OPTARG);;
        x) format='xml';;
        \?) echo  >&2
            usage >&2
            exit 1;;
    esac
    done

# Vérification des options
if [[ -z $query ]]
then
    echo "Erreur : option(s) manquante(s)" >&2
    echo "" >&2
    usage >&2
    echo ""
    exit 2
fi

if [[ -z $sortie ]]
then
    sortie='/dev/null'
elif [[ $sortie = '-' ]]
then
    sortie='/dev/fd/1'
fi

if [[ -z $cookiejar ]]
then
    cookiejar='cookies.txt'
fi

# Vérification de la présence des programmes
# “curl”, “jq” et “xmllint”
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

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

# Vérification de la variable “$max”
max=${nrec:-5}

if [[ $max -lt 0 ]]
then
    echo "Erreur : le nombre de notices par itération doit être compris entre 0 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

# 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
    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 [[ ${#bases[@]} -gt 0 ]]
then
    for item in ${bases[@]}
    do
        while [[ -n $item ]]
        do
            deb=${item%%,*}
            fin=${item#*,}
            if [[ $deb =~ ^[A-Z]+:[A-Z]+$ ]]
            then
                coll=${deb%:*}
                edit=${deb#*:}
            else
                coll='WOS'
                edit=$deb
            fi
            if [[ -n $edition ]]
            then
                edition="$edition,$coll+$edit"
            else
                edition="$coll+$edit"
            fi
            if [[ $deb = $fin ]]
            then
                item=""
            else
                item=$fin
            fi
        done
    done
    extra="$extra, \"edition\": \"$edition\""
fi

if [[ -n $cdate || -n $mdate || -n $pdate ]]
then
    if [[ -n $cdate ]]
    then
        if [[ -n $ldate || -n $mdate || -n $pdate ]] 
        then
            erreur=$(( $erreur + 1 ))
        else
            label='createdTimeSpan'
            option='-c'
            span=$cdate
        fi
    fi
    if [[ -n $mdate ]]
    then
        if [[ -n $ldate || -n $pdate ]] 
        then
            erreur=$(( $erreur + 1 ))
        else
            label='modifiedTimeSpan'
            option='-m'
            span=$mdate
        fi
    fi
    if [[ -n $pdate ]]
    then
        if [[ -n $ldate ]] 
        then
            erreur=$(( $erreur + 1 ))
        else
            label='publishTimeSpan'
            option='-p'
            span=$pdate
        fi
    fi
    if [[ $erreur -gt 0 ]]
    then
        echo " " >&2
        echo "Erreur : présence de plusieurs options indiquant une période" >&2
        echo " " >&2
        usage >&2
        echo " " >&2
        exit 4
    fi
    regex="[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])"
    if [[ $span =~ ^$regex:$regex$ ]]
    then
        begin=${span%:*}
        end=${span#*:}
        # Vérification de la validité de chaque date
        for i in $begin $end
        do
            day=$(date -d $i 2> /dev/null)
            if [[ -z $day ]]
            then
                echo ""
                echo "Erreur : date “$i” invalide" >&2
                echo " " >&2
                exit 4
            fi
        done
        extra="$extra, \"$label\": \"$begin+$end\""
    else
        echo " " >&2
        echo "Erreur : argument incorrect pour l’option “$option”" >&2
        echo " " >&2
        exit 4
    fi
fi

if [[ -n $ldate ]]
then
    if [[ $ldate =~ ^([0-6]D|([1-9]|[1-4][0-9]|5[0-2])W|([1-9]|1[0-2])M|([0-9]|10)Y)$ ]]
    then
        extra="$extra, \"loadTimeSpan\": \"$ldate\""
    else
        echo ""
        echo "Erreur : argument incorrect pour l’option “-l”" >&2
        echo " " >&2
        exit 4
    fi
fi

if [[ ${#tri[@]} -gt 0 ]] 
then
    for item in ${tri[@]}
    do
        while [[ -n $item ]]
        do
            deb=${item%%,*}
            fin=${item#*,}
            if [[ ! $deb =~ ^(AU|CF|CG|CW|CV|LC|LD|PG|PY|SO|VL):[AD]$ && ! $deb =~ ^(RS|TC):D$ ]]
            then
                echo "Erreur : argument incorrect pour pour l’option “-t”" >&2
                exit 4
            fi
            nom=${deb%%:*}
            sens=${deb#*:}
            if [[ -n $sortField ]]
            then
                sortField="$sortField,$nom+$sens"
            else
                sortField="$nom+$sens"
            fi

            if [[ $deb = $fin ]]
            then
                item=""
            else
                item=$fin
            fi
        done
    done
    extra="$extra, \"sortField\": \"$sortField\""
fi

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

# Nettoyage en cas d’arrêt prématuré
trap nettoie HUP INT QUIT TERM

# Lancement de la requête
requete="${query//\"/\\\"}"

cat << EOT > search$$.json
{
  "databaseId": "WOS",
  "lang": "en",
  "usrQuery": "$requete",
  "count": $max,
  "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
        code=$(perl -ne 'print "$1" if /"code": "(.+?)"/o' $out)
        if [[ -n $code ]]
        then
            msg="$code: $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)

            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

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

echo " " >&2
echo "Identifiant de la requête : $qid" >&2
(echo "Nombre de notices trouvées : $rec / $top notices"
 echo "Forfait restant : $amt"
 echo "") |
    perl -pe '1 while(s/(\d)(\d\d\d)\b/$1 $2/o);' >&2

nettoie


exit 0