Nous avons vu précédemment comment parser du XML , il est également possible de parser du HTML et l'outil qui fait le mieux le job selon moi c'est le librairy BeautifulSoup
Qui dit lib python dit pip
pip install beautifulsoup4
BeautifulSoup vous propose par exemple de récupérer toutes les balises p d'une page HTML
# coding: utf-8 from bs4 import BeautifulSoup html_doc = """ <html> <head> <title>Titre de votre site</title> </head> <body> <p>Texte à lire 1</p> <p>Texte à lire 2</p> </body> </html> """ soup = BeautifulSoup(html_doc) for p in soup.find_all('p'): print p
Ce qui retournera:
<p>Texte à lire 1</p> <p>Texte à lire 2</p>
Trouver les éléments qui nous intéresse c'est une chose, mais pouvoir les modifier c'est encore mieux!
# coding: utf-8 from bs4 import BeautifulSoup html_doc = """ <html> <head> <title>Titre de votre site</title> </head> <body> <p>Texte à lire 1</p> <p>Texte à lire 2</p> </body> </html> """ soup = BeautifulSoup(html_doc) for p in soup.find_all('p'): p.string = "Nouveau texte" print soup
Résultat:
<html> <head> <title>Titre de votre site</title> </head> <body> <p>Nouveau texte</p> <p>Nouveau texte</p> </body> </html>
Vous pouvez remplacer les balises avec la méthode replace_with :
# coding: utf-8 from bs4 import BeautifulSoup html_doc = """ <html> <head> <title>Titre de votre site</title> </head> <body> <p>Texte à lire 1</p> <p>Texte à lire 2</p> </body> </html> """ soup = BeautifulSoup(html_doc) for p in soup.find_all('p'): n = BeautifulSoup('<pre>%s</pre>' % p.string) p.replace_with(n.body.contents[0]) print soup
Réponse du script:
<html> <head> <title>Titre de votre site</title> </head> <body> <pre>Texte à lire 1</pre> <pre>Texte à lire 2</pre> </body> </html>
Il est possible de lire les attributs des éléments avec la méthode get :
# coding: utf-8 from bs4 import BeautifulSoup html_doc = """ <html> <head> <title>Titre de votre site</title> </head> <body> <p class="c1 c2">Texte à lire 1</p> <p class="c3">Texte à lire 2</p> </body> </html> """ soup = BeautifulSoup(html_doc) for p in soup.find_all('p'): print p.get("class")
Résultat:
>>> ['c1', 'c2'] >>> ['c3']
Extrait tous les enfants
Créer un rendu en chaine unicode
Detruit récursivement les contenus de l'arbre
encode
Créer des rendus du tag en bytestring
Retourne seulement le premier enfant de la balise correspondant pour le critère donné
Retourne une liste d'objet balise correspondant à la demande.
Retourne seulement le premier enfant de la balise cherchée
Retourne une liste d'objet balise correspondant à la demande
Retourne la valeur de l'attribut "key" de la balise ou retourne la valeur default
Retourne toutes les chaines de caractères des enfants concaténé utilisant le séparateur indiqué
True si l'attribut demandé est présent
Vérifie la présence de la clé
Retourne l'index de l'élément
Améliore la lecture du code
Ajoute la balise donnée à l'objet en cours
Extrait l'élément de l'arbre
Renvoi les objects frères de l'objet en cours
Renvoi les parents
Retourne tous les items qui match avec le critère donné avant l'objet en cours
Retourne les objets frères de l'objet en cours qui sont avant celui-ci
Retourne les objets qui correpondent à la recherche mais qui se situent après l'objet en cours
Retourne les objets qui correspondent à la recherche mais qui se situent avant l'objet en cours
Retourne le premier objet frère après l'objet en cours
Retourne l'objet frère le plus proche après lui
Retourne les objets frères suivants
Retourne le parent le plus proche
Retourne les parents
Retourne le premier item avant l'objet en cours
Retourne l'item frère le plus proche précédent l'objet en cours
Retourne les items frères les plus proches précédents l'objet en cours
Retourne tous les items qui suivent l'objet en cours
Retourne tous les items qui précédent l'objet en cours
J'avais besoin d'un parseur HTML pour mettre en forme et colorer le code que je présente sur ce site; je partage ce petit script:
# coding: utf-8 import sys import glob from bs4 import BeautifulSoup from pygments import highlight from pygments.lexers import PythonLexer from pygments.formatters import HtmlFormatter def pygments_file(pathname): # On ouvre le fichier with open(pathname, "r" ) as f: html_doc = f.read() soup = BeautifulSoup(html_doc) # On boucle sur les pre trouvés for pre in soup.find_all('pre'): try: if "code" in pre.get("class"): texte = highlight(pre.get_text(), PythonLexer(), \ HtmlFormatter(nowrap=True)) n = BeautifulSoup('%s' % texte) pre.replace_with(n.body.contents[0]) except: print("Erreur avec {}".format(pre,)) if soup.body: with open(pathname, "w") as f: f.write(soup.body.encode_contents()) p = "/home/olivier/*.html" if sys.argv[1]: p = str(sys.argv[1]) pathnames = glob.glob(p) for pathname in pathnames: pygments_file(pathname)
Vous pouvez aussi bien lui renseigner un dossier qu'un seul fichier.
Livres Python & Django: conseils de lecture