IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

ElementTree probleme de parsage d'un document html


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 4
    Par défaut ElementTree probleme de parsage d'un document html
    Bonjour,
    j'essaie d'utiliser un script eqhtml.py qui permet d'inserer des equations dans un document html en passant par un script python qui effectue la conversion au prealable (il lance latex sur chaque equation, qu'il convertit en image) :

    http://www.fauskes.net/nb/htmleqII/#the_code

    Ca marche presque a la perfection, le seul probleme, c'est qu'initialement, mon fichier html aura cette tete :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
     
    <head>
    <title>Test</title>
    <link rel="stylesheet" href="guide.css" type="text/css"/>
    <link href="prettify.css" type="text/css" rel="stylesheet"/>
    <script type="text/javascript" src="prettify.js"></script>
    </head>
     
    <body onload="prettyPrint()">
     
     
    <div class="eq">
    \int_a^b \, f(x) \, dx \, = \, \sum_{k=1}^N \int_{x_k}^{x_{k+1}} \,
    f(x) \, dx \, = \, \sum_{k=1}^N \, \sum_{j=1}^{r+1} \, \omega_j
    (x_{k+1}-x_k) f( (1-\xi_j)x_{k} + \xi_j x_{k+1})
    </div>
     
    </body>
    </html>


    Et a la sortie, j'obtiens le fichier suivant :



    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <html:html lang="en" xml:lang="en" xmlns:html="http://www.w3.org/1999/xhtml">
     
    <html:head>
    <html:title>Test</html:title>
    <html:link href="guide.css" rel="stylesheet" type="text/css" />
    <html:link href="prettify.css" rel="stylesheet" type="text/css" />
    <html:script src="prettify.js" type="text/javascript" />
    </html:head>
     
    <html:body onload="prettyPrint()">
     
     
    <html:div class="eq"><img alt="" src="eqtest1.png" /></html:div>
     
    </html:body>
    </html:html>

    Bon, la je me mefie pas trop, je me dis que le navigateur va se debrouiller avec ca, ben en fait pas du tout. Il n'aime pas du tout les balises html:body, html:div, il prefere body et div. Donc je voudrais savoir comment on fait pour ne pas mettre ces html: partout lorsqu'on fait une sortie avec ElementTree d'un fichier html. Pour le moment, je vire tous ces html: avec emacs, mais c'est "manuel" (enfin j 'enleve tout d'un coup, mais faut taper la commande pour chaque fichier converti.

    Voila, si vous avez une solution a proposer ...
    Merci

  2. #2
    Membre Expert
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Par défaut
    Si j'ai bien compris,

    un fichier sourcefn (contenant le document HTML initial que tu présentes en exemple) est ouvert par
    f = open(sourcefn) ,
    parsé par
    xhtmltree = ElementTree.parse(f) ,
    puis les éléments de xhtmltree qui sont des équations mathématiques sont extraits,
    traités par LaTeX ,
    et enregistrés dans un fichier texfn ,
    en même temps que les équations dans le document sont remplacées par des adresses url d'images.
    Puis la compilation du fichier texfn par
    os.system('latex %s' % texfn)
    produit un fichier DVI.

    Ensuite je comprends que dvipng traite ce fichier DVI par
    cmd = "dvipng -T tight -x 1200 -z 9 -bg transparent " \
    + "-o %seq%s%%d.png %s" % (imgpath , sourcefn_base, sourcefn_base)
    os.system(cmd)

    mais je ne comprends pas quel est l'effet de cette instruction.

    Le document xhtmltree après modification est enregistré dans le fichier destnfn par
    xhtmltree.write(destfn)
    et je comprends qu'il s'agit du deuxième document HTML que tu présentes, avec des erreurs de balises.




    1
    Dans ce circuit, je ne sais pas à quel endroit les balises sont transformées. Est-ce lors du traitement par ElementTree ? ou par LaTeX ? Il faudrait quelqu'un connaissant ces outils pour dire s'il est envisageable d'ajouter du code pour éviter la transformation déficiente des balises au moment où elle se produit ou avant d'enregistrer par xhtmltree.write(destfn) le document traité.
    C'est la première piste, mais je ne sais pas faire et j'ai vu une discussion dans laquelle quelqu'un voulait faire ce genre de modification d'un tree en utilisant les fonctions de ElementTree ou de DOM ou autre parseur, sans y arriver.





    2

    À défaut, une seconde piste est de corriger les balises incorrectes dans le document obtenu, après son traitement et son enregistrement, en le réouvrant sous forme 'texte' et non pas 'tree'.
    Je propose deux manières de le faire



    * l'une sommaire, consistant à simplement éliminer toutes les occurences de la chaîne 'html:'
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    f = open('xhtml.html','r')
    ch = f.read().replace('html:',"")
    g = open('xhtml corrige.html','w')
    g.write(ch)
    f.close()
    g.close()
    et si le fichier est volumineux
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    f = open('xhtml.html','r')
    g = open('xhtml corrige.html','w')
    for ln in f:
        g.write(ln.replace('html:',""))
    f.close()
    g.close()
    Mais cette manière est un peu trop fruste pour inspirer confiance: et s'il y a des 'html:' dans le fichier qui ne sont pas des chaines de balises ? Ils seront tout de même éliminés.






    * une deuxième manière plus chirurgicale utilisant le exrpressions régulières

    Elle tire profit du fait que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for u in ElementTree.parse('htmldoc.html').getiterator():
    fournit les uns après les autres les instances-éléments du document parsés, qui, d'après ce que j'ai constatés correspondent à toutes les balises ouvrantes,
    et au fait que ElementTree.tostring(u) donne l' instance u sous forme de chaîne commençant par la balise.
    Or d'aprs ce que je constate, c'est que ce sont les noms de balises qui se retrouvent avec un 'html:' superflu.

    Il suffit donc d'itérer sur les tostring(u) pour faire une liste des balises afin de construire une Regex compilée spécifique au document traité, dont l'écriture est donc automatisée à partir des balises que le programme trouve lui-même dans le document. Ce qui évite d'avoir à faire une recherche préalable de tous les types de balises susceptibles d'être présentes dans un document html quelconque et d'alourdir la regex avec des balises inutiles pour un document.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    import re
    import xml.etree.ElementTree as et
     
    parshtml = et.parse('htmldoc.html')
     
    reoNomBalise = re.compile('<html:([a-z]+?) ')
    toutes_balises = []
    for u in parshtml.getiterator():
        m = reoNomBalise.match(et.tostring(u))
        if m:
            toutes_balises.append(m.group(1))
    baliz = list(set(toutes_balises))
    print '\nbalises  : ',baliz
     
    REbaliz = 'html:(' + '|'.join(baliz) + ')'
    print '\nREbaliz =  ' + REbaliz
    reoBaliz = re.compile(REbaliz)
    f = open('htmldoc.html')
    g = open('htmldoc corrige.html','w')
    for ln in f:
        m = reoBaliz.search(ln)
        if m:
            g.write(reoBaliz.sub(m.group(1),ln))
        else:
            g.write(ln)
    f.close()
    g.close()
     
     
    print '\nDOCUMENT APRES CORRECTION DES BALISES:\n'
    f = open('htmldoc corrige.html')
    for ln in f:
        print ln[0:-1]
    f.close()



    Remarques:



    - Dans un premier temps, j'avais cherché à éliminer les 'html:' en recherchant le premier blanc dans une balise ouvrante, dans le document ouvert en texte, pour trouver le nom de la balise et être en mesure de corriger non seulement les balises ouvrantes en débuts de lignes mais aussi les balises fermantes qui peuvent ètre en fin de ligne comme </html:div>. Mais le problème est que les balises des éléments
    <html:head>
    <html:title>Test</html:title>
    en mode texte
    n'ont pas de blanc.
    De plus la présence de / dans les balises fermante compliquait les choses.





    - Dans un deuxième temps, j'ai donc été obligé de faire appel aux regex, mais j'avais écrit une mauvaise RE qui attrapait le nom de la balise <img
    parce que <img alt="" src="eqtest1.png" /> est consciencieusement listé aussi par et.tostring(u) .
    alors que cette balise B]<img [/B] n'est pas concernee par les 'html:' superflus.
    Il faut se méfier de ce genre de cas, c'est pourquoi le html: en dehors des parenthèses dans la RE est important.



    - Finalement en faisant tourner le code suivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    parshtml = et.parse('htmldoc.html')
    for u in parshtml.getiterator():
        print et.tostring(u)
    on peut obsrver que, quel que soit l'élément u du tree, tostring(u) écrit les bidules type=" ", src=" ", onload=" ', class=" ", etc présents dans les balises ouvrantes par ordre alphabétique (ce qui n'a aucune importance pour nous),
    mais surtout en ajoutant systématiquement xmlns:html="http://www.w3.org/1999/xhtml" comme bidule supplémentaire même quand il n'est pas présent dans la balise ouvrante.
    Ce bidule xmlns:html="http://www.w3.org/1999/xhtml" se trouve uniquement dans la balise ouvrante du premier élement et se trouve dans l'instance renvoyée par parshtml.getroot().
    J'ai testé: ce bidule xmlns:html=" " est toujours ajouté à la fin de et.tostring(u) , c'est à dire qu'il échappe à la classification des bidules par ordre alphabétique.
    Mais peu importe.
    L'important à remarquer c'est que comme ce bidule xmlns:html="http://www.w3.org/1999/xhtml" est toujours présent dans et.tostring(u) , le nom de chaque balise ouvrante est suivi d'un blanc ' ' dans et.tostring(u), même pour les balises ouvrantes sans bidules comme <html:head> ou <html:title> .
    C'est important uniquement pour écrire la RE de reoNomBalise


    Finalement l'ajout systématique du bidule xmlns:html="http://www.w3.org/1999/xhtml" qui introduit un blanc apporte une simplification de l'écriture de la RE et tout se goupille bien.



    - Une fois qu'on a toutes les balises dans toutes_balises, on élimine les doubles en faisant baliz = list(set(toutes_balises))


    - Ensuite c'est bateau.
    Il faut surtout bien mettre le 1 dans group(1) pour remplacer html:titre par titre, sinon ça remplace par le match complet c'est à dire .... html:titre !

    - Il reste le problème du xmlns:html persistant parce que html se trouve à la fin et non au début comme pour les noms de balises.
    Il faut voir s'il perturbe la lecture du document corrigé par le navigateur. Si c'est le cas, on s'occupera de lui, je n'en ai pas envie pour le moment.

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 4
    Par défaut
    Merci beaucoup pour ta reponse, c'est tres instructif. J'avoue que j'avais besoin de faire ca assez vite, du coup j'ai zappe l'utilisation de elementtree car ca posait des pbs (ca me virait aussi les instructions php, ce qui me rendait pas super heureux). Bon, c'est un script assez bourinasse, puisque je fais une detection tres basique de la balise html dont j'ai besoin, mais ca me convient tres bien pour ce que je voulais faire.

    L'instruction dvipng sert en fait a separer le dvi en plusieurs fichiers png (un fichier par equation). Enfin bref, merci de ton aide, ca m'a fait comprendre que elementtree c'etait un truc bien complique, et qu'il fallait vraiment en avoir besoin pour essayer de modifier ce machin :p

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
     
    """A simple tool for embedding LaTeX in XHTML documents.
     
    This script lets you embed LaTeX code between <div> and <span> tags. Example:
        <div class="eq>
          y = \int_0^\infty \gamma^2 \cos(x) dx 
        </div>
        <p> An inline equation <span class="eq">y^2=x^2+\alpha^2</span> here.</p>
     
    The script extracts the equations, creates a temporary LaTeX document, 
    compiles it, saves the equations as images and replaces the original markup 
    with images.
     
    Usage:
        python eqhtml.py source dest
        
    Process source and save result in dest. Note that no error checking is 
    performed. 
    """
     
    import os, sys
     
    # Include your favourite LaTeX packages and commands here
    tex_preamble = r'''
    \documentclass{article} 
    \usepackage{amsmath}
    \usepackage{amsthm}
    \usepackage{amssymb}
    \usepackage{bm}
    \newcommand{\mx}[1]{\mathbf{\bm{#1}}} % Matrix command
    \newcommand{\vc}[1]{\mathbf{\bm{#1}}} % Vector command 
    \newcommand{\T}{\text{T}}                % Transpose
    \pagestyle{empty} 
    \begin{document} 
    '''
     
    imgpath = 'equation/' # path to generated equations. e.q 'img/'
     
    # get source and dest filenames from command line
    sourcefn = sys.argv[1]
    destfn = sys.argv[2]
    sourcefn_base = os.path.splitext(os.path.basename(sourcefn))[0]
    # change working directory to the same as source's
    cwd = os.getcwd()
    os.chdir(os.path.abspath(os.path.dirname(sourcefn)))
    sourcefn = os.path.basename(sourcefn)
    texfn = sourcefn_base+'.tex'
     
    print "Processing %s" % sourcefn
    # load source document
    f = open(sourcefn)
    docphp = f.readlines();
    f.close()
     
    # find all elements with attribute class='eq'
    # eqs will contain all the equations
    eqs = []
    chaine_debut = '<div class="eq">'
    chaine_fin = '</div>'
    lecture_equation = 0
    # new lines will be written in newdoc_php
    newdoc_php = []
    counter = 0
    for ligne in docphp:
        if chaine_debut in ligne:
            # beginning of an equation
            lecture_equation = 1
            counter = counter+1
            # delete LaTeX code from the document, and replace
            # them by image urls.
            imgname = "%seq%s%i.png" % (imgpath, sourcefn_base, counter)
            ligne_image = '<div class="eq"><img alt="" src="%s" /></div>\n' % (imgname)
            newdoc_php.append(ligne_image)
            # initialization of eq (on the first line, no latex symbols)
            eq = ""   
        elif (lecture_equation == 1):
            if chaine_fin in ligne:
                # end of the equation
                index = ligne.find(chaine_fin);
                eq = eq + (ligne[0:index]);
                lecture_equation = 0
                eqs.append(eq)
            else:
                eq = eq + ligne
        else:
            newdoc_php.append(ligne)
     
     
    # equations are now available in the eqs[..] variable
     
    # create a LaTeX document and insert equations
    f = open(texfn,'w')
    f.write(tex_preamble)
    counter = 1
    for eq in eqs:
        f.write("\\[ %s \\] \n \\newpage \n" % eq)
        counter += 1
    # end LaTeX document    
    f.write('\end{document}')
    f.close()
     
    # compile LaTeX document. A DVI file is created
    os.system('latex %s' % texfn)
     
    # Run dvipng on the generated DVI file. Use tight bounding box. 
    # Magnification is set to 1200
    cmd = "dvipng -T tight -x 1200 -z 9 -bg transparent " \
    + "-o %seq%s%%d.png %s" % (imgpath , sourcefn_base, sourcefn_base)
    os.system(cmd) 
     
     
     
    # Remove temporary files
    os.remove(sourcefn_base+'.tex')
    os.remove(sourcefn_base+'.log')
    os.remove(sourcefn_base+'.aux')
    os.remove(sourcefn_base+'.dvi')
     
    os.chdir(cwd)
     
    # Write processed source document to dest 
    f = open(destfn,'w')
    for ligne in newdoc_php:
        f.write(ligne)
    f.close()
     
     
    print "Done."

Discussions similaires

  1. Générateur de document HTML et PDF a partir d'un fichier XML
    Par Fildz dans le forum XML/XSL et SOAP
    Réponses: 1
    Dernier message: 03/03/2006, 17h55
  2. [SAX] IOException sur la parsage d'un document
    Par inertia dans le forum Format d'échange (XML, JSON...)
    Réponses: 4
    Dernier message: 11/02/2006, 13h22
  3. [FPDF] Convertion en d'un document HTML en PDF
    Par Cube55 dans le forum Bibliothèques et frameworks
    Réponses: 1
    Dernier message: 02/02/2006, 18h16
  4. exportation d'une valeur dans un document html
    Par acd dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 28/11/2005, 21h34
  5. [DOM] Parser un document Html distant
    Par le Daoud dans le forum Format d'échange (XML, JSON...)
    Réponses: 3
    Dernier message: 02/05/2005, 14h19

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo