diff --git a/README.md b/README.md index ffc8aeb..ba4ffea 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ Outil d’extraction de corpus ISTEX -Permet de décharger un corpus de fichiers textes (PDF, TEI, TXT), de fichiers de -métadonnées (JSON, Mods, XML) ou de fichiers d’enrichissement depuis la base ISTEX +Permet de décharger un corpus de fichiers textes (PDF, [TEI](https://fr.wikipedia.org/wiki/Text_Encoding_Initiative), TXT), de fichiers de +métadonnées ([JSON](https://fr.wikipedia.org/wiki/JavaScript_Object_Notation), [MODS](https://fr.wikipedia.org/wiki/Metadata_Object_Description_Schema), XML) ou de fichiers d’enrichissement depuis la base ISTEX à partir d’une requête ou d’un fichier [`.corpus`](#1---fichier-). Permet également de renommer les fichiers déchargés et de générer un fichier de notices bibliographiques. @@ -23,10 +23,10 @@ ``` harvestCorpus.pl -q 'requête' [ -a | -emt [,]* ] [ -d destination ] [ -n [notices.txt]] [ -p préfixe ] [ -s fichier.corpus ] - [ -l nombre ] [ -r [nombre]] [ -iv ] [ -j jeton ] + [ -l nombre ] [ -r [nombre]] [ -iv ] [ -j jeton ] [ -z [gzip|bzip2]] harvestCorpus.pl -c fichier.corpus ( -a | -emt [,]* ) [ -d destination ] [ -n [notices.txt]] [ -p préfixe ] [ -l nombre ] - [ -j jeton ] + [ -f nombre ] [ -j jeton ] [ -z [gzip|bzip2]] harvestCorpus.pl -h ``` @@ -40,7 +40,12 @@ -h affiche cette aide -e liste les enrichissements à télécharger, soit “all” pour l’ensemble, soit “abesAuthors”, “abesSubjects”, “multicat”, “nb”, “refBibs”, “teeft” ou “unitex” - -i ajoute l’indexation automatique, e.g. TEEFT, dans les notices bibliographiques + -f indique à partir de quel numéro de document, on télécharge les fichiers, mais + seulement avec l’option “-c”. + ATTENTION : numérotation informatique qui commence à “0”. Pour avoir les fichiers + à partir du document n° “50 001”, utiliser la valeur “50 000” ! + -i utilise l’identifiant ISTEX à la place de l’identifiant ARK dans le fichier + “fichier.corpus” -j indique le jeton d’authentification obtenu sur “https://api.istex.fr/token/” -l limite le nombre maximum de documents téléchargés au nombre fourni en argument -m liste les fichiers de métadonnées à télécharger, soit “all” pour l’ensemble, @@ -49,7 +54,9 @@ “notices.txt” dans le répertoire courant ou celui donné par l’option “-d”) -p indique le préfixe utilisé pour renommer les fichiers téléchargés (par défaut, “f”). Ce préfixe est ensuite suivi d’un numéro séquentiel et de l’extension correspondant - au type de document téléchargé + au type de document téléchargé. Si la valeur de l’option “-p” est “0”, alors + le fichier garde son nom original, c’est-à-dire l’identifiant ISTEX, mais pas + en présence de l’option “-c” -q indique la requête à utiliser, entre simples quotes en présence de blancs ou de caractères spéciaux (incompatible avec l’option “-c”) -r provoque une sortie dans un ordre aléatoire en fonction d’une “graine” aléatoire @@ -62,12 +69,15 @@ soit “ocr”, “pdf”, “tei”, “txt” ou “zip” -v garde les métadonnées ISTEX au format JSON dans un fichier “logRequete.txt” dans le répertoire courant ou celui donné par l’option “-d” + -z indique le nom du programme à utiliser pour compresser les fichiers générés, + à savoir “logRequete.txt”, “id.corpus”, “notices.txt” ou équivalents. Par + défaut, utilise “gzip” ``` ### Authentification -Le téléchargement de certains fichiers, notamment le texte intégral, à partir d’ISTEX n’est autorisé qu’aux membres de l’ESR. Si vous n’avez pas une authentification par adresse IP, il vous faut obtenir un jeton d’accès à l’adresse “**https://api.istex.fr/token/**”. Après avoir sélectionné votre organisme de tutelle et vous être identifié, vous serez dirigé vers une page au format JSON contenant deux “clés” : +Le téléchargement de certains fichiers, notamment le texte intégral, à partir d’ISTEX n’est autorisé qu’aux membres de l’ESR (**E**nseignement **S**upérieur et **R**echerche). Si vous n’avez pas une authentification par adresse IP, il vous faut obtenir un jeton d’accès à l’adresse “**https://api.istex.fr/token/**”. Après avoir sélectionné votre organisme de tutelle et vous être identifié, vous serez dirigé vers une page au format JSON contenant deux “clés” : - “*_comment*” : indication sur l’emploi du jeton d’accès (à ne pas suivre dans le cas présent), - “*_accessToken*” : donnant le jeton d’accès à utiliser avec l’option `-j`. @@ -95,9 +105,18 @@ harvestCorpus.pl -c Biofutur.corpus -m mods -d Metadata ``` +> Téléchargement dans le répertoire “**FichiersTEI**” des fichiers **TEI** par paquet de 25 000 à partir du fichier **`Elsevier/els.corpus`** contenant les identifiants de tous les documents issus d’Elsevier : + +```bash + harvestCorpus.pl -c Elsevier/els.corpus -t tei -d FichiersTEI -l 25000 + harvestCorpus.pl -c Elsevier/els.corpus -t tei -d FichiersTEI -l 25000 -f 25000 + harvestCorpus.pl -c Elsevier/els.corpus -t tei -d FichiersTEI -l 25000 -f 50000 + ... +``` + #### 3 - Tirage aléatoire -> Création d’un échantillon de 1000 fichiers textes provenant d’Elsevier, choisi de façon aléatoire, et génération du fichier `Elsevier/els.corpus` et du fichier de notices bibliographiques `Elsevier/els.txt` : +> Création d’un échantillon de 1000 fichiers textes provenant d’Elsevier, choisi de façon aléatoire, et génération du fichier **`Elsevier/els.corpus`** et du fichier de notices bibliographiques **`Elsevier/els.txt`** : ```bash harvestCorpus.pl -q corpusName:elsevier -t txt,ocr -d Elsevier -p els -n -l 1000 -r @@ -112,7 +131,7 @@ Par défaut, ce fichier se nomme `id.corpus` ou `préfixe.corpus` en présence de l’option `-p` et il se trouve soit dans le répertoire courant, soit dans le répertoire indiqué par l’option `-d`. -Le texte ci-dessous correspond au début du fichier `Elsevier/els.corpus` obtenu avec l’exemple “[3 - Tirage aléatoire](#3---tirage-aléatoire)”. +Le texte ci-dessous correspond au début du fichier **`Elsevier/els.corpus`** obtenu avec l’exemple “[3 - Tirage aléatoire](#3---tirage-aléatoire)”. ```text # @@ -138,9 +157,35 @@ ... ``` +Avec l’option `-i`, la même commande aurait donné le fichier **`Elsevier/els.corpus`** suivant : + +```text +# +# Fichier .corpus +# +title : <à compléter> +author : BESAGNI +publisher : <à compléter> +query : corpusName:elsevier +date : Mardi 6 Mars 2018 09:52:50 +license : CC-By ? +versionInfo : 1.0 ? +randomSeed : 1520326370561 +total : 1000 / 6015985 documents + +[ISTEX] +id 0ACFDDBB83BF9A5ABAD34686AC4C8CE9317BDB2E # els00001 +id 742E33D5C0485C08A9CDE3425557F8B28B81A0D3 # els00002 +id 001199848185C5FF5B9E98701DD619C43676D84E # els00003 +id 639E8121432DECC831D632BF35C3BE8245CAF309 # els00004 +id 90F958B4490A91E16E673FA96C0503604A9295E6 # els00005 +id CF9E6012BD4F0F15F34B87C4F65DF4E43D7A3621 # els00006 +... +``` + #### 2 - Fichier `logRequete.txt` -Avec l’option `-v`, il est possible de conserver l’ensemble des informations envoyées par l’API ISTEX lors de l’exécution d’une requête. Ces métadonnées sont conservées dans le fichier `logRequete.txt` qui se trouve soit dans le répertoire courant, soit dans le répertoire indiqué par l’option `-d`. +Avec l’option `-v`, il est possible de conserver l’ensemble des métadonnées au format JSON envoyées par l’API ISTEX lors de l’exécution d’une requête. Ces métadonnées sont conservées dans le fichier `logRequete.txt` qui se trouve soit dans le répertoire courant, soit dans le répertoire indiqué par l’option `-d`. Ce fichier est notamment utilisé par le programme [`statsCorpus.pl`](../../tree/master/outils/stats-corpus) pour extraire les principales informations concernant chaque document du corpus, comme le titre, le nom du périodique, la date de publication, l’éditeur, la version de PDF, etc. diff --git a/harvestCorpus.pl b/harvestCorpus.pl index 63eebfa..711d4c7 100755 --- a/harvestCorpus.pl +++ b/harvestCorpus.pl @@ -22,24 +22,25 @@ my $usage = "Usage : \n" . " $programme -q 'requête' [ -a | -emt [,]* ]\n" . " $substitut [ -d destination ] [ -n [notices.txt]] [ -p préfixe ] [ -s fichier.corpus ] \n" . - " $substitut [ -l nombre ] [ -r [nombre]] [ -iv ] [ -j jeton ]\n" . + " $substitut [ -l nombre ] [ -r [nombre]] [ -iv ] [ -j jeton ] [ -z [gzip|bzip2]]\n" . " $programme -c fichier.corpus ( -a | -emt [,]* ) \n" . " $substitut [ -d destination ] [ -n [notices.txt]] [ -p préfixe ] [ -l nombre ] \n" . - " $substitut [ -j jeton ]\n" . + " $substitut [ -f nombre ] [ -j jeton ] [ -z [gzip|bzip2]]\n" . " $programme -h \n\n"; -my $version = "4.2.3"; -my $dateModif = "6 Mars 2018"; +my $version = "4.3.1"; +my $dateModif = "7 Avril 2018"; # Variables my $aide = 0; my $all = 0; my $corpus = ""; my $destination = "."; -my $indexation = 0; +my $from = 0; +my $gardeId = 0; +my $istexId = 0; my $jeton = ""; my $limite = 0; -my $prefixe = ""; my $quiet = 0; my $requete = ""; my $rien = 0; @@ -52,7 +53,9 @@ # Variables indéfinies au départ my $notices = undef; +my $prefixe = undef; my $random = undef; +my $zip = undef; eval { $SIG{__WARN__} = sub {usage(1);}; @@ -61,8 +64,9 @@ "corpus=s" => \$corpus, "destination=s" => \$destination, "enrichissements=s" => \@enrichissements, + "from=i" => \$from, "help" => \$aide, - "indexation" => \$indexation, + "istexId" => \$istexId, "jeton=s" => \$jeton, "limite=i" => \$limite, "metadonnees=s" => \@metadonnees, @@ -73,6 +77,7 @@ "source=s" => \$source, "texte=s" => \@types, "verbeux" => \$verbeux, + "zip:s" => \$zip, ); }; $SIG{__WARN__} = sub {warn $_[0];}; @@ -86,24 +91,31 @@ print " \n"; print $usage; print "Options : \n"; - print " -a télécharge tous les fichiers correspondants aux documents\n"; + print " -a télécharge tous les fichiers correspondants aux documents \n"; print " -c utilise le fichier “fichier.corpus” comme source d’identifiants pour télécharger \n"; - print " les documents (incompatible avec les options “-r” et “-s”)\n"; + print " les documents (incompatible avec les options “-r” et “-s”) \n"; print " -d indique le répertoire de destination des documents (répertoire courant par défaut)\n"; - print " -h affiche cette aide\n"; + print " -h affiche cette aide \n"; print " -e liste les enrichissements à télécharger, soit “all” pour l’ensemble, soit \n"; - print " “abesAuthors”, “abesSubjects”, “multicat”, “nb”, “refBibs”, “teeft” ou “unitex”\n"; - print " -i ajoute l'indexation automatique, e.g. TEEFT, dans les notices bibliographiques\n"; - print " -j indique le jeton d’authentification obtenu sur “https://api.istex.fr/token/”\n"; - print " -l limite le nombre maximum de documents téléchargés au nombre fourni en argument\n"; + print " “abesAuthors”, “abesSubjects”, “multicat”, “nb”, “refBibs”, “teeft” ou “unitex” \n"; + print " -f indique à partir de quel numéro de document, on télécharge les fichiers, mais \n"; + print " seulement avec l’option “-c”. ATTENTION : numérotation informatique qui commence \n"; + print " à “0”. Pour avoir les fichiers à partir du document n° “50 001”, utiliser la \n"; + print " valeur “50 000” ! \n"; + print " -i utilise l’identifiant ISTEX à la place de l’identifiant ARK dans le fichier \n"; + print " “fichier.corpus” \n"; + print " -j indique le jeton d’authentification obtenu sur “https://api.istex.fr/token/” \n"; + print " -l limite le nombre maximum de documents téléchargés au nombre fourni en argument \n"; print " -m liste les fichiers de métadonnées à télécharger, soit “all” pour l’ensemble, \n"; - print " soit “json”, “mods” ou “xml”\n"; - print " -n crée un fichier de notices bibliographiques (sans argument, crée le fichier\n"; - print " “notices.txt” ou “préfixe.corpus” (cf. option “-p”) dans le répertoire courant ou \n"; - print " celui donné par l’option “-d”)\n"; + print " soit “json”, “mods” ou “xml” \n"; + print " -n crée un fichier de notices bibliographiques (sans argument, crée le fichier \n"; + print " “notices.txt” ou “préfixe.txt” (cf. option “-p”) dans le répertoire courant ou \n"; + print " celui donné par l’option “-d”) \n"; print " -p indique le préfixe utilisé pour renommer les fichiers téléchargés (par défaut, “f”).\n"; print " Ce préfixe est ensuite suivi d'un numéro séquentiel et de l'extension correspondant \n"; - print " au type de document téléchargé \n"; + print " au type de document téléchargé. Si la valeur de l’option “-p” est “0”, alors \n"; + print " le fichier garde son nom original, c’est-à-dire l’identifiant ISTEX, mais pas en \n"; + print " présence de l’option “-c” \n"; print " -q indique la requête à utiliser, entre simples quotes en présence de blancs ou de \n"; print " caractères spéciaux (incompatible avec l’option “-c”)\n"; print " -r provoque une sortie dans un ordre aléatoire en fonction d'une “graine” aléatoire \n"; @@ -115,8 +127,11 @@ print " -t liste les fichiers de texte intégral à télécharger, soit “all” pour l’ensemble, \n"; print " soit “ocr”, “pdf”, “tei”, “txt” ou “zip”\n"; print " -v garde les métadonnées ISTEX au format JSON dans un fichier “logRequete.txt” dans \n"; - print " le répertoire courant ou celui donné par l’option “-d”\n\n"; - print "Exemple : \n"; + print " le répertoire courant ou celui donné par l’option “-d”\n"; + print " -z indique le nom du programme à utiliser pour compresser les fichiers générés, \n"; + print " à savoir “logRequete.txt”, “id.corpus”, “notices.txt” ou équivalents. Par \n"; + print " défaut, utilise “gzip” \n\n"; + print "Exemples : \n"; print " $programme -q '(host.title:\"Biofutur\" OR host.issn:\"0294-3506\")' -t pdf,tei \n"; print " $substitut -d FichiersPDF -s Biofutur.corpus -p biofutur -v\n"; print " $programme -c Biofutur.corpus -m mods -d Metadata\n\n"; @@ -160,10 +175,20 @@ usage(7); } -if ( $prefixe ) { - if ( $prefixe !~ /^[A-Za-z](\w*-)?\w+\z/ ) { +if ( defined $prefixe ) { + if ( not $prefixe ) { + if ( $requete ) { + $gardeId ++; + } + else { + $prefixe = "f"; + print STDERR "Attention : l’option “-p 0” n’est pas compatible avec l’option “-c”.\n"; + print STDERR " ⇒ utilisation de la valeur par défaut “f”.\n"; + } + } + elsif ( $prefixe !~ /^[A-Za-z](\w*-)?\w+\z/ ) { $prefixe = "f"; - print STDERR "Erreur : préfixe non-conforme ⇒ utilisation de la valeur par défaut.\n"; + print STDERR "Attention : préfixe non-conforme ⇒ utilisation de la valeur par défaut.\n"; } } else { @@ -190,8 +215,31 @@ } } +if ( defined $zip ) { + if ( not $zip ) { + $zip = "gzip"; + } + elsif ( $zip =~ /^(gzip|bzip2)\z/i ) { + $zip = lc($zip); + } + else { + print STDERR "Erreur : \"$zip\" n’est pas une valeur acceptable pour l’option “-z” !\n"; + usage(8); + } + } +my %extension = ( + "bzip2" => "bz2", + "gzip" => "gz", + ); + if ( $verbeux ) { - open(LOG, ">:raw", "$destination/logRequete.txt") or die "$!,"; + if ( $zip ) { + open(LOG, "| $zip -c -9 > $destination/logRequete.txt.$extension{$zip}") or die "$!,"; + binmode(LOG, ":utf8"); + } + else { + open(LOG, ">:raw", "$destination/logRequete.txt") or die "$!,"; + } } else { open(LOG, "> /dev/null") or die "$!,"; @@ -271,14 +319,26 @@ # Ouverture du fichier de notices bibliographiques if ( $notices ) { - open(OUT, ">:utf8", $notices) or die "$!,"; + if ( $zip ) { + open(OUT, "| $zip -c -9 > $notices.$extension{$zip}") or die "$!,"; + binmode(OUT, ":utf8"); + } + else { + open(OUT, ">:utf8", $notices) or die "$!,"; + } } if ( $requete ) { # Ouverture en écriture du fichier “.corpus” if ( $source ) { my $date = date(); - open(SRC, ">:utf8", $source) or die "$!,"; + if ( $zip ) { + open(SRC, "| $zip -c -9 > $source.$extension{$zip}") or die "$!,"; + binmode(SRC, ":utf8"); + } + else { + open(SRC, ">:utf8", $source) or die "$!,"; + } print SRC "#\n# Fichier .corpus\n#\n"; print SRC "title : <à compléter> \n"; print SRC "author : "; @@ -361,7 +421,7 @@ } else { print STDERR "Pas de \"scrollId\"\n"; - exit 6; + exit 10; } my @hits = @{$top{'hits'}}; foreach my $hit (@hits) { @@ -375,12 +435,12 @@ else { print OUT "# Nombre de réponses : 0\n#\n\n" if $notices; print STDERR "Aucun document pour la requête \"$requete\"\n"; - exit 4; + exit 11; } } else { print STDERR "Aucune réponse du serveur \"$base\"\n"; - exit 5; + exit 12; } # Itérations suivantes @@ -418,7 +478,7 @@ } else { print STDERR "Aucune réponse du serveur \"$base\"\n"; - exit 5; + exit 13; } } @@ -489,7 +549,25 @@ my $suite = 0; my $type = ""; - open(INP, "<:utf8", $corpus) or die "Impossible d'ouvrir \"$corpus\" : $!,"; + $limite += $from; + if ( not -f $corpus ) { + print STDERR "Erreur : fichier \"$corpus\" absent\n"; + exit 14; + } + elsif ( $corpus =~ /\.g?[zZ]\z/ ) { + open(INP, "gzip -cd $corpus |") or + die "Erreur : Impossible d'ouvrir \"$corpus\" : $!,"; + binmode(INP, ":utf8"); + } + elsif ( $corpus =~ /\.bz2\z/ ) { + open(INP, "bzip2 -cd $corpus |") or + die "Erreur : Impossible d'ouvrir \"$corpus\" : $!,"; + binmode(INP, ":utf8"); + } + else { + open(INP, "<:utf8", $corpus) or + die "Erreur : Impossible d'ouvrir \"$corpus\" : $!,"; + } while() { chomp; s/\r//go; @@ -521,6 +599,7 @@ } elsif ($istex and /^ark +/o) { $num ++; + next if $num <= $from; ($type, $ark, $sep, $nom) = split(/\s+/); if ( $nom ) { $nom{$ark} = $nom; @@ -532,6 +611,7 @@ } elsif ($istex and /^id +/o) { $num ++; + next if $num <= $from; ($type, $id, $sep, $nom) = split(/\s+/); if ( $nom ) { $nom{$id} = $nom; @@ -621,7 +701,7 @@ } else { print STDERR "Erreur : $message pour URL \"$cible\"\n"; - exit 3; + exit 15; } } @@ -638,8 +718,17 @@ my $extension = ""; if ( $source ) { - my $racine = $prefixe . sprintf($format, $num); - if ( $hit{'arkIstex'} ) { + my $racine = "";$prefixe . sprintf($format, $num); + if ( $gardeId ) { + $racine = $hit{'id'}; + } + else { + $racine = $prefixe . sprintf($format, $num); + } + if ( $istexId ) { + print SRC "id $hit{'id'} # $racine\n"; + } + elsif ( $hit{'arkIstex'} ) { print SRC "ark $hit{'arkIstex'} # $racine\n"; } else { @@ -788,7 +877,7 @@ } else { print STDERR "Pas de \"scrollId\"\n"; - exit 6; + exit 16; } my @hits = @{$top{'hits'}}; foreach my $hit (@hits) { @@ -932,6 +1021,9 @@ if ( $nom ) { $fichier = "$nom$extension"; } +elsif ( $gardeId ) { + $fichier = "$id$extension"; + } elsif ( $rang ) { $fichier = "$prefixe" . sprintf($format, $rang) . "$extension"; } @@ -1257,21 +1349,21 @@ } } -# Champ AI (Automatic Indexing) -if ( $indexation and $top{'keywords'} ) { - my %keywords = %{$top{'keywords'}}; - if ( defined $keywords{'teeft'} ) { - my @tmp = sort {length($a) <=> length($b) or $a cmp $b} @{$keywords{'teeft'}}; - my %tmp = (); - for (my $nb = 0 ; $nb < $#tmp ; $nb ++) { - if ( grep(/\b$tmp[$nb]\b/, @tmp[$nb + 1 .. $#tmp]) == 0 ) { - $tmp{$tmp[$nb]} ++; - } - } - $ligne = "AI : " . join(" ; ", grep {defined $tmp{$_}} @{$keywords{'teeft'}}); - push(@lignes, $ligne); - } - } +# # Champ AI (Automatic Indexing) +# if ( $indexation and $top{'keywords'} ) { +# my %keywords = %{$top{'keywords'}}; +# if ( defined $keywords{'teeft'} ) { +# my @tmp = sort {length($a) <=> length($b) or $a cmp $b} @{$keywords{'teeft'}}; +# my %tmp = (); +# for (my $nb = 0 ; $nb < $#tmp ; $nb ++) { +# if ( grep(/\b$tmp[$nb]\b/, @tmp[$nb + 1 .. $#tmp]) == 0 ) { +# $tmp{$tmp[$nb]} ++; +# } +# } +# $ligne = "AI : " . join(" ; ", grep {defined $tmp{$_}} @{$keywords{'teeft'}}); +# push(@lignes, $ligne); +# } +# } # Champ LO $ligne = "NO : ISTEX $top{'id'}";