web-dev-qa-db-fra.com

Python code pour supprimer les balises HTML d'une chaîne

J'ai un texte comme ça:

text = """<div>
<h1>Title</h1>
<p>A long text........ </p>
<a href=""> a link </a>
</div>"""

en utilisant du Python pur, sans module externe, je veux avoir ceci:

>>> print remove_tags(text)
Title A long text..... a link

Je sais que je peux le faire en utilisant lxml.html.fromstring (text) .text_content () mais je dois atteindre le même résultat en pure Python en utilisant la bibliothèque intégrée ou std pour la version 2.6+.

Comment puis je faire ça?

104

Utiliser une regex

En utilisant une regex, vous pouvez tout nettoyer à l'intérieur de <>:

import re

def cleanhtml(raw_html):
  cleanr = re.compile('<.*?>')
  cleantext = re.sub(cleanr, '', raw_html)
  return cleantext

Certains textes HTML peuvent également contenir des entités qui ne sont pas entre crochets, telles que '&nsbm'. Si tel est le cas, vous pouvez écrire la regex sous la forme suivante:

cleanr = re.compile('<.*?>|&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-f]{1,6});')

Ce lien contient plus de détails à ce sujet.

Utiliser BeautifulSoup

Vous pouvez également utiliser BeautifulSoup package supplémentaire pour trouver tout le texte brut

Vous aurez besoin de définir explicitement un analyseur lors de l'appel de BeautifulSoup. Je recommande "lxml" comme indiqué dans les réponses alternatives (beaucoup plus robuste que celui par défaut (c'est-à-dire disponible sans installation supplémentaire) "html.parser"

from bs4 import BeautifulSoup
cleantext = BeautifulSoup(raw_html, "lxml").text

Mais cela ne vous empêche pas d'utiliser des bibliothèques externes, je recommande donc la première solution.

188
c24b

Python a plusieurs modules XML intégrés. Le plus simple pour le cas où vous avez déjà une chaîne avec le code HTML complet est xml.etree , ce qui fonctionne (un peu) de manière similaire à l'exemple lxml que vous avez mentionné :

_def remove_tags(text):
    return ''.join(xml.etree.ElementTree.fromstring(text).itertext())
_
34
lvc

Notez que ce n’est pas parfait, car si vous aviez quelque chose comme, par exemple, _<a title=">">_, cela casserait. Cependant, c'est à peu près tout ce que vous obtiendrez dans une non-bibliothèque Python sans une fonction vraiment complexe:

_import re

TAG_RE = re.compile(r'<[^>]+>')

def remove_tags(text):
    return TAG_RE.sub('', text)
_

Cependant, comme le mentionne lvc xml.etree est disponible dans la bibliothèque standard Python, de sorte que vous pourriez probablement l'adapter pour servir comme votre version existante lxml:

_def remove_tags(text):
    return ''.join(xml.etree.ElementTree.fromstring(text).itertext())
_
28
Amber

Il existe un moyen simple d’y parvenir dans n’importe quel langage semblable à C. Le style n'est pas Pythonic mais fonctionne avec du Python pur:

def remove_html_markup(s):
    tag = False
    quote = False
    out = ""

    for c in s:
            if c == '<' and not quote:
                tag = True
            Elif c == '>' and not quote:
                tag = False
            Elif (c == '"' or c == "'") and tag:
                quote = not quote
            Elif not tag:
                out = out + c

    return out

L'idée, basée sur une simple machine à états finis, est expliquée ici: http://youtu.be/2tu9LTDujbw

Vous pouvez le voir fonctionner ici: http://youtu.be/HPkNPcYed9M?t=35s

PS - Si la classe vous intéresse (sur le débogage intelligent avec Python), je vous donne un lien: http://www.udacity.com/overview/Course/cs259/CourseRev/1 . C'est gratuit!

6
Medeiros