La recette d'un script réussi
La première étape de notre étude consistait à récolter un maximum de données textuelles qui se devaient d'être correctement organisées.
Pour cela, nous avons été formés à la syntaxe du bash ainsi qu'à l'utilisation des outils disponibles sous les systèmes d'exploitation Unix/Linux au long d'un semestre de cours à Paris 3.
Cela nous aura permi d'apprendre à user d'outils indispensables dans l'avancement de notre script. Ainsi c'est par le biais de diverses commandes que nous avons pu donner une première
étincelle à notre projet.
L'outil le moins dispensable de notre travail se révèle être la commande -curl, qui nous permet de télécharger directement
une page html depuis une adresse url, suivie de la commande iconv nous permettant de convertir en utf-8 l'encodage des pages aspirées. Ensuite la commande -lynx qui nous permet de filtrer une page html pour n'en récupérer que le texte brut et enfin la commande
-egrep qui nous permet de chercher les occurences d'un caractère ou d'une chaîne de caractères dans un texte. Une pléthore d'autres commandes ont été utilisées, vous les découvrirez dans le script directement !
Des outils supplémentaires nous ont été d'une aide précieuse, notamment lorsqu'il s'agit de traiter le chinois ou le japonais. Il y a tout d'abords
Janome, un segmenteur syntaxique pour le japonais, indispensable pour traiter les mots indépendamment.
On a ensuite Stanford Segmenter, qui lui nous permet de segmenter le chinois.
Puis, Minigrep Multilingue qui sert à relever les occurences d'un motif dans un texte et à les mettre en contexte les uns avec les autres.
Enfin nous avons utilisé Python 3 pour corriger les éventuelles erreurs ou manque des outils précédents.
Prérequis
Pour pouvoir faire fonctionner le script qui va suivre sur une machine (système Unix uniquement), il va falloir installer les différents outils donnés précédemment.
Il faudra donc utiliser les commandes qui suivent.
Pour Python 3 :-sudo apt-get install python3
Pour pip3 (module de Python) :-sudo apt-get install python3-pip
Pour Janome (une version plus récente ne sera pas supportée) :-pip3 install Janome==0.3.9
Pour Lynx :-sudo apt-get install lynx
Pour Perl :-sudo apt-get install perl
Pour Stanford segmenter :
Il faut télécharger la dernière version ici et décompresser l'archive dans le même répertoire que le script et on renomme le dossier extrait "stanford-segmenter".
Pour minigrep-multilingue :
Télécharger la dernière version ici. On décompresse "minigrepmultilingue-v2.2-regexp.zip" dans le répertoire courant,
on décompresse ensuite l'archive "Unicode-String-2.10.tar.gz". On se rend enfin dans le dossier décompressé du même nom et on utilise les commandes suivantes :-perl Makefile.PL
-make
-make install
En cas de problème on peut consulter ce tutoriel.
Recours à Python
Python nous a été très utile lorsqu'il s'agissait de segmenter les données en japonais. Mais il a été d'autant plus utile lorsqu'il nous a permis de corriger les erreurs liées
à l'encodage du chinois et du japonais en utf-8. La présence de certains sinogrammes ou caractères nous empêchant les segmenteurs syntaxiques de découper les données recueillies dans ces langues en unités syntaxiques, nous
avons du écrire ces deux scripts et les inclure dans notre script bash ci-dessous afin de rendre entièrement fonctionnel ce dernier. Afin de les utiliser, vous devrez les enregistrer au format ".py" dans le même répertoire que le script bash
et au nom indiqué en première ligne du code.
Ces scripts sont les suivants :
#byte_repair.py
import codecs
file = 'repair.txt'
list = []
with codecs.open(file, 'r', encoding='utf-8', errors='ignore') as f:
for line in f :
list.append(line)
with open(file, 'w') as file :
for item in list :
file.write(f"{item}")
#japonais_segmenteur.py
file = 'japout.txt'
list = []
with open(file, 'r') as f :
for line in f :
data = line.split('\t')
word = data[0]
list.append(word)
with open(file, 'w') as out :
cpt_item = 0
for item in list :
cpt_item += 1
out.write(f"{item} ")
if cpt_item == 25 :
out.write("\n")
cpt_item = 0
Un script en bash
La principale fonction de notre script est donc de lire un fichier d'URLs, une par ligne et de construire un tableau en html pour chaque fichier dont le nom correspond au motif recherché dans le corpus des pages html récoltées. Le
tableau ainsi généré comportera diverses informations et indiquera l'emplacement des données traitées par notre script. Les résultats tirés de nos fichirs d'URLs se trouvent dans la section suivante.
Une fois les prérequis remplis et les scripts python mis en place, on peut essayer le script ci-dessous en utilisant la commande suivante sur le répertoire où se trouve le script :
-bash nomduscript.sh ./URLS ./TABLEAUX
Le script :
#!/bin/bash
# on commence par supprimer l'éventuel fichier de résultat que l'on doit reconstruire
rm -f "$2/tableau.html" ;
# on récupère les 2 arguments que l'on a passé au programme
# le premier : chemin vers le dossier contenant les fichiers d'URL
# le second : chemin vers le dossier devant contenir le fichier HTML final
echo "Les urls SONT DANS : $1" ;
echo "On créé le tableau HTML dans : $2" ;
echo "TABLEAU D'URLs " >> "$2/tableau.html";
# Création d'une variable pour compter les fichiers traités et donc le nb du tableau généré
# cette variable sera utilisée pour créer les noms de fichiers associés à chaque URL
numerotableau=1;
#----------------------------------------------------------------
# Parcours du dossier contenant les fichiers URLs
for fichier in $(ls $1)
do
MOTIF=$(echo "$fichier" | cut -d "." -f2);
MOTIF=$(echo "$MOTIF" | sed -e "s/_/ /"); #Le motif correspond au nom du fichier d'urls, la partie entre deux points comme suit : langue-.motif.txt. Il faut remplacer les _ par des espaces pour correctement lire le motif
echo "Le motif du fichier est : $MOTIF";
echo "MOTIF=$MOTIF" > ./minigrep/parametre-motif.txt; #On écrit le motif.
compteur=1; # compteur destiné à compter les URLs pour chaque fichier d'URL
echo "$1/$fichier" ;
#-----------------------------------------------------------
# Création du tableau associé au fichier en cours de traitement
#-----------------------------------------------------------
echo " " >> "$2/tableau.html" ;
echo "Syntagme : $MOTIF " >> "$2/tableau.html";
echo "N° URL Code http encodage Page aspirée Dump Filtrage Txt Filtrage Html Index Bitexte Fq Motif " >> "$2/tableau.html" ;
#----------------------------------------------------------------
# "parcours" d'un fichier d'URL : lecture ligne à ligne des URLs
for ligne in $(cat "$1/$fichier")
do
echo "----------------------------------------------";
echo "Traitement de l'URL : $ligne";
echo "----------------------------------------------";
#-----------------------------------------------------------
# 1. on teste la connexion vers l'URL : récupération de http_code via curl
#-----------------------------------------------------------
# Il faut faire attention aux caractères de contrôle pouvant être présents dans l'url et les supprimer si nécéssaire.
ligne=$(echo "$ligne" | sed -e "s/\r//")
coderetourhttp=$(curl -SIL -o tmp.txt -w %{http_code} $ligne);
echo "CODE HTTP : $coderetourhttp";
# si coderetourhttp est egale à 200
if [[ $coderetourhttp == 200 ]]
then
#-----------------------------------------------------------
# 2. on essaie de récupérer l'encodage de la page associée à l'URL
# REMARQUE : la commande suivante est lancée que si http_code=200
#-----------------------------------------------------------
encodage=$(curl -sIL -o toto -w %{content_type} $ligne | cut -f2 -d"=" | tr '[a-z]' '[A-Z]' | tr -d '\r');
echo "ENCODAGE DETECTE PAR CURL : $encodage";
#-----------------------------------------------------------
# 3. on récupère la page localement et on la range dans le bon dossier
#-----------------------------------------------------------
curl -L -o "./PAGES-ASPIREES/$numerotableau-$compteur.html" "$ligne";
#Si curl ne trouve pas lencodage, on passe par egrep
if [[ $encodage == "TEXT/HTML" ]]
then
encodage=$(egrep -io "charset=\"?[^\",]+\"?" ./PAGES-ASPIREES/$numerotableau-$compteur.html | cut -f2 -d "=" | tr -d '("|\\|>)' | sed "s/'//g" | sort | uniq);
fi
#On uniformise les indications en utf8.
if [[ $encodage =~ .*(u|U)(T|t)(f|F)-8.* ]]
then
sed "s/[Uu][Tt][Ff]-8/UTF-8/g" ./PAGES-ASPIREES/$numerotableau-$compteur.html > ./PAGES-ASPIREES/encodageout.html;
mv ./PAGES-ASPIREES/encodageout.html ./PAGES-ASPIREES/$numerotableau-$compteur.html;
encodage="UTF-8";
fi
#Si l'encodage n'est pas utf8 on converti le fichier avec iconv en utf8.
if [[ $encodage != "UTF-8" ]]
then
encodage=$(egrep -io "charset=\"?[^\",]+\"?" ./PAGES-ASPIREES/$numerotableau-$compteur.html | cut -f2 -d "=" | tr -d '("|\\|>)' | sed "s/'//g" | sort | uniq);
echo "L'encodage de la page est : $encodage";
sed "s/$encodage/UTF-8/g" ./PAGES-ASPIREES/$numerotableau-$compteur.html > ./PAGES-ASPIREES/encodageout.html;
iconv -c -f $encodage -t UTF-8 < ./PAGES-ASPIREES/encodageout.html > ./PAGES-ASPIREES/$numerotableau-$compteur.html;
encodage=$(egrep -io "charset=\"?[^\",]+\"?" ./PAGES-ASPIREES/$numerotableau-$compteur.html | cut -f2 -d "=" | tr -d '("|\\|>)' | sed "s/'//g" | tr '[a-z]' '[A-Z]' | sort | uniq);
fi
if [[ $encodage =~ "UTF-8" ]]
then
#-----------------------------------------------------------
# On remplit le tableau : 1 ligne par URL et autant de colonnes que de traitement réalisés
# Pour le dump via LYNX on travaille sur la page aspirée
#-----------------------------------------------------------
# 1. On lynx la page aspirée
lynx -dump -nolist -assume_charset=$encodage -display_charset=$encodage "./PAGES-ASPIREES/$numerotableau-$compteur.html" > ./DUMP-TEXT/$numerotableau-$compteur.txt;
# Un # en tant que premier caractère d'un fichier à lire empêche python ou janome de s'exécuter.
sed "s/#/ /" < ./DUMP-TEXT/$numerotableau-$compteur.txt > repair.txt;
python3 byte_repair.py;
mv repair.txt ./DUMP-TEXT/$numerotableau-$compteur.txt;
#On va supprimer les bytes qui n'aurait pas pu être bien converties en utf-8 (pas d'équivalent ou lynx qui se plante ou erreur du site lui-même). Ca ne concerne que quelques octets pour quelques urls (-5) donc ça ne gène pas.
#-----------------------------------------------------------
#Si le fichier sortie de lynx est en japonais, on sépare les mots avec le programme linux janome et on sépare les mots par des espaces avec un script python (car le module janome de python ne marche pas)
if [[ "$fichier" =~ jp-.* ]]
then
janome < ./DUMP-TEXT/$numerotableau-$compteur.txt > japout.txt;
python3 japonais_segmenteur.py;
fi
if [[ "$fichier" =~ cn-.* ]]
then
bash ./stanford-segmenter/segment.sh -k ctb ./DUMP-TEXT/$numerotableau-$compteur.txt "UTF-8" "0" > chinout.txt;
fi
# 2. On cree le fichier contexte TXT via egrep
egrep -i -C2 "$MOTIF" ./DUMP-TEXT/$numerotableau-$compteur.txt > ./CONTEXTES/$numerotableau-$compteur.txt;
#-----------------------------------------------------------
# 3. Fq motif
nbmotif=$(egrep -coi "$MOTIF" ./DUMP-TEXT/$numerotableau-$compteur.txt;);
#-----------------------------------------------------------
# 4. contexte html
perl ./minigrep/minigrepmultilingue.pl "utf-8" ./DUMP-TEXT/$numerotableau-$compteur.txt ./minigrep/parametre-motif.txt ;
mv resultat-extraction.html ./CONTEXTES/$numerotableau-$compteur.html ;
#-----------------------------------------------------------
#On remplace les fichiers dumps par les fichiers dumps segmentés une fois le fichier contexte généré et la fréquence du motif compté.
if [[ "$fichier" =~ jp-.* ]]
then
mv japout.txt ./DUMP-TEXT/$numerotableau-$compteur.txt;
fi
if [[ "$fichier" =~ cn-.* ]]
then
mv chinout.txt ./DUMP-TEXT/$numerotableau-$compteur.txt;
fi
#-----------------------------------------------------------
# 5. index hierarchique
egrep -o "\w+" ./DUMP-TEXT/$numerotableau-$compteur.txt | sort | uniq -c | sort -r > ./DUMP-TEXT/index-$numerotableau-$compteur.txt ;
#-----------------------------------------------------------
# 6. bigramme
egrep -o "\w+" ./DUMP-TEXT/$numerotableau-$compteur.txt > bi1.txt;
tail -n +2 bi1.txt > bi2.txt ;
paste bi1.txt bi2.txt > bi3.txt ;
cat bi3.txt | sort | uniq -c | sort -r > ./DUMP-TEXT/bigramme-$numerotableau-$compteur.txt ;
#-----------------------------------------------------------
# 7. on écrit les résultats dans le tableau avec tous les résultats produits
echo "
$compteur
$ligne
Code_http:$coderetourhttp
Encodage:$encodage
$numerotableau-$compteur.html
$numerotableau-$compteur.txt
$numerotableau-$compteur.txt
$numerotableau-$compteur.html
index-$numerotableau-$compteur
bigramme-$numerotableau-$compteur
$nbmotif
" >> "$2/tableau.html";
#-----------------------------------------------------------
else
#-----------------------------------------------------------
#-----------------------------------------------------------
echo "$compteur $ligne Code_http:$coderetourhttp Encodage:$encodage $numerotableau-$compteur.html - - - - - - " >> "$2/tableau.html";
fi
else
#-----------------------------------------------------------
# Ici on a un URL pas OK (code http différent de 200,
# Cette URL ne sera pas traitée
# on la laisse dans le tableau avec des colonnes vides !!!!
#-----------------------------------------------------------
echo "$compteur $ligne Code_http:$coderetourhttp - - - - - - - - " >> "$2/tableau.html";
fi
#Concaténation des fichiers dump
echo "Concaténation des fichiers DUMP-TEXT $numerotableau";
#Balise html pour indiquer le début de chaque fichier dump (pour itrameur entre autres).
echo "" >> ./DUMP-TEXT/dump-concat-$numerotableau.txt;
#On concatène
cat ./DUMP-TEXT/$numerotableau-$compteur.txt >> ./DUMP-TEXT/dump-concat-$numerotableau.txt;
#Balise pour indiquer la fin de chaque fichier dump.
echo " " >> ./DUMP-TEXT/dump-concat-$numerotableau.txt;
#Concaténation des fichiers contextes.
echo "Concaténation des fichiers CONTEXTE $numerotableau";
#Balise html pour indiquer le début de chaque fichier contexte (pour itrameur entre autres).
echo "" >> ./CONTEXTES/contextes-concat-$numerotableau.txt;
#On concatène
cat ./DUMP-TEXT/$numerotableau-$compteur.txt >> ./CONTEXTES/contextes-concat-$numerotableau.txt;
#Balise pour indiquer la fin de chaque fichier dump.
echo " " >> ./CONTEXTES/contextes-concat-$numerotableau.txt;
# on incrémente le compteur des URLs
compteur=$((compteur+1)) ;
#Fin du parcours d'un ficher d'URLs.
done
#Ecriture des résultats de la concaténation :
echo "
dump_concat.txt
contexte_concat.txt
" >> "$2/tableau.html";
#----------------------------------------------------------------
echo "
" >> "$2/tableau.html" ;
# on incrémente le compteur de tableaux
numerotableau=$((numerotableau+1));
#Fin de l'itération sur chaque fichier d'URLs.
done
#----------------------------------------------------------------
echo "" >> "$2/tableau.html" ;
exit;
#fin du programme
Résultats
Vous pouvez trouver les tableaux sur lesquels se basent les propos de la section "Analyse" en cliquant
ici. Certaines pages peuvent avoir été supprimées, bien que prises en compte dans l'analyse, entre la récolte de données et le rendu final des tableaux ainsi qu'entre
la création de ce site et son visionnage à l'instant présent.