Boîte à outil 2 : étiquetage

Ici nous présentons le script Python pour étiqueter le corpus avec TreeTagger. Nous utilisons la sortie XML produite avec la BAO1.

Préparation d'environnement


In [ ]:
import treetaggerwrapper, os
from bs4 import BeautifulSoup

# on initialise le wrapper en indiquant le chemin du TreeTagger et la langue traitée
tagger = treetaggerwrapper.TreeTagger(TAGDIR='C:/TreeTagger', TAGLANG='fr')

TreeTagger n'a pas d'implémentation directe dans Python, cependant il existe un wrapper développé par Laurent Pointal au sein de CNRS-LIMSI. Pour utiliser ce wrapper, il faut que TreeTagger soit installé dans le système a priori. Si l'installation n'est pas faite dans l'un des emplacements par défaut, il faut préciser le chemin du répertoire TreeTagger avec le paramètre TAGDIR. Ensuite on indique la langue du fichier à parser avec le paramètre TAGLANG.

Nous utilisons également BeautifulSoup pour exploiter la sortie xml.

Boucle principale : étiquetage


In [ ]:
# on parcourt le répertoire de sortie
for root, dirs, files in os.walk('./SORTIE_V10'):
    for name in files :
        if name.endswith('.xml'):
            # on choisit les fichiers xml, on récupère leur chemin et on produit le nom du fichier de sortie
            filename = os.path.join(root,name)
            newname = 'ttg-' + name

Nous parcourons l'arborescence produite précédemment. Vous pouvez toutefois préciser le chemin vers une certaine rubrique pour que le programme n'étiquète que celle qui vous intéresse. Nous travaillons sur les fichiers xml, donc nous avons mis une condition pour trier les fichiers. A chaque rencontre d'un fichier xml, nous prenons son chemin pour la lecture et son nom pour la sortie.

Variables générées : filename (chemin du fichier xml), newname (fichier de sortie)

In [ ]:
            # on ouvre le fichier xml et la sortie
            with open(filename,'r',encoding='UTF8') as lecture, open(newname,'w',encoding='UTF8',newline='\n') as sortie:

                # on initialise la sortie
                sortie.write("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<file>\n")
                
                # on parse le xml
                soup = BeautifulSoup(lecture, 'lxml-xml')
                archives = soup.find_all('archive')
                

Nous ouvrons le fichier xml et le passons au parseur BeautifulSoup. En même temps, nous créons le fichier de sortie et nous initialisons le format xml. Dans notre fichier xml, chaque article est noté avec une balise <archive>, donc nous cherchons toutes ces balises.

Variables générées : archives (liste des balises <archive>)

In [ ]:
                # on prend une balise <archive> et on initialise la balise <item> dans la sortie
                for archive in archives:
                    sortie.write("<item number=\"{}\">\n".format(archive["n"]))

Pour chaque article, il faut une balise <item> correspondant dans la sortie quoi qu'il arrive. Nous prenons également le numéro d'archive et le mettons dans la sortie.

In [ ]:
                    # on récupère la balise <title> sous la balise <archive>
                    title = archive.title
    
                    # on vérifie s'il existe bien un titre
                    if title and title.string:
                        
                        # on initialise la balise <titre>
                        sortie.write("<titre>\n<article>\n")
                        
                        # on appelle TreeTagger et on étiquète la phrase
                        tags = tagger.tag_text(title.string)
                        
                        # on prend chaque ligne de tableau et on convertit en xml
                        for tag in tags:
                            eles = tag.split('\t')
                            
                            if len(eles) == 3:
                                tag_parsed = """<element>
                                <data type="type">{0}</data>
                                <data type="lemma">{1}</data>
                                <data type="string">{2}</data>
                                </element>""".format(eles[1], eles[2].replace('&', '&amp;'), eles[0].replace('&', '&amp;'))
                            else:
                                tag_parsed = """<element>
                                <data type="type">{0}</data>
                                <data type="lemma">{1}</data>
                                <data type="string">{2}</data>
                                </element>""".format('_', '_', eles[0])
                                
                            sortie.write(tag_parsed + '\n')
                        
                        #on finalise la balise <titre>
                        sortie.write("</article>\n</titre>\n")

C'est ici que se passent l'étiquetage et la transformation du format. Le wrapper nous renvoie une sortie tabulaire, il nou faudrait les transformer en format xml. Heureusement tous les deux formats sont clairement structurés, ce qui facilite beaucoup la conversion.

Chaque balise <archive> est composée d'une balise <titre> et d'une balise <description>. Nous réalisons le même traitement dans l'ordre pour toutes les deux. Nous prenons le texte de la balise et faisons parser par TreeTagger. Il y a des éléments comme LeMonde.fr qui sont traités d'une manière spéciale : ils sont remplacés avec une balise <repdns>. Vu que notre traitement est basé sur les tabulations, cette analyse posera problème. Pour régler ce problème, nous les mettons directement dans la sortie en lui attribuant manuellement un POS tag et un lemme.

La structure xml est complétée au fur et à mesure.

In [ ]:
                    # on prend la balise <description> sous la balise <archive>
                    description = archive.description
        
                    # on vérifie qu'il existe bien une description
                    if description and description.string:
                    
                        # on initialise la balise <description>
                        sortie.write("<description>\n<article>\n")
                        
                        # on appelle TreeTagger et fait parser la phrase
                        tags = tagger.tag_text(title.string)
                        
                        # on convertit le format
                        for tag in tags:
                            eles = tag.split('\t')
                            if len(eles) == 3:
                                tag_parsed = """<element>
                                <data type="type">{0}</data>
                                <data type="lemma">{1}</data>
                                <data type="string">{2}</data>
                                </element>""".format(eles[1], eles[2].replace('&', '&amp;'), eles[0].replace('&', '&amp;'))
                            else:
                                tag_parsed = """<element>
                                <data type="type">{0}</data>
                                <data type="lemma">{1}</data>
                                <data type="string">{2}</data>
                                </element>""".format('_', '_', eles[0])
                           
                        # on finalise la balise <description>
                        sortie.write("</article>\n</description>\n")
                        
                    # on finalise la balise <item>
                    sortie.write("</item>\n")
                
                # on finalise la balise <file>
                sortie.write("</file>")

Nous réalisons le même traitement pour les descriptions. En sortant d'un article nous fermons la balise <item> et en sortant du fichier xml, la balise <file>.