Les cuisines du TAL

Notre script et nos outils


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 "<html><head><meta charset=\"utf-8\" /><title>TABLEAU D'URLs</title></head><body>" >> "$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 "<table border=\"2\" align=\"center\" width=\"80%\">" >> "$2/tableau.html" ;
echo "<tr><td colspan=\"11\" align=\"center\" bgcolor=\"orange\">Syntagme : $MOTIF</td></tr>" >> "$2/tableau.html";
echo "<tr bgcolor=\"orange\"><td>N°</td><td>URL</td><td>Code http</td><td>encodage</td><td>Page aspirée</td><td>Dump</td><td>Filtrage Txt</td><td>Filtrage Html</td><td>Index</td><td>Bitexte</td><td>Fq Motif</td></tr>" >> "$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 "<tr>
			<td>$compteur</td>
			<td><a href=\"$ligne\" target=\"_blank\">$ligne</a></td>
			<td>Code_http:$coderetourhttp</td>
			<td>Encodage:$encodage</td>
			<td><a href=\"../PAGES-ASPIREES/$numerotableau-$compteur.html\">$numerotableau-$compteur.html</a></td>
			<td><a href=\"../DUMP-TEXT/$numerotableau-$compteur.txt\">$numerotableau-$compteur.txt</a></td>
			<td><a href=\"../CONTEXTES/$numerotableau-$compteur.txt\">$numerotableau-$compteur.txt</a></td>
			<td><a href=\"../CONTEXTES/$numerotableau-$compteur.html\">$numerotableau-$compteur.html</a></td>
			<td><a href=\"../DUMP-TEXT/index-$numerotableau-$compteur.txt\">index-$numerotableau-$compteur</a></td>
			<td><a href=\"../DUMP-TEXT/bigramme-$numerotableau-$compteur.txt\">bigramme-$numerotableau-$compteur</a></td>
			<td>$nbmotif</td>
			</tr>" >> "$2/tableau.html";
			#-----------------------------------------------------------
			else
			#-----------------------------------------------------------
			#-----------------------------------------------------------
			echo "<tr><td>$compteur</td><td><a href=\"$ligne\" target=\"_blank\">$ligne</a></td><td>Code_http:$coderetourhttp</td><td>Encodage:$encodage</td><td><a href=\"../PAGES-ASPIREES/$numerotableau-$compteur.html\">$numerotableau-$compteur.html</a></td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>" >> "$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 "<tr><td>$compteur</td><td><a href=\"$ligne\" target=\"_blank\">$ligne</a></td><td>Code_http:$coderetourhttp</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>" >> "$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=$numerotableau-$compteur.txt>" >> ./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>" >> ./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 "<contexte=$numerotableau-$compteur.txt>" >> ./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 "</contexte>" >> ./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 "<tr><td></td><td></td><td></td><td></td><td></td>
<td><a href=\"../DUMP-TEXT/dump-concat-$numerotableau.txt\" target=\"_blank\">dump_concat.txt</a></td>
<td><a href=\"../CONTEXTES/contextes-concat-$numerotableau.txt\" target=\"_blank\">contexte_concat.txt</a></td>
<td></td><td></td><td></td><td></td>
</tr>" >> "$2/tableau.html";

	#----------------------------------------------------------------
echo "</table><br />" >> "$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 "</body></html>" >> "$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.

Copyright © 2019-2020 Paris 3 - Designed by Arthur