Version courte!
import re, cgi
tag_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
# Remove well-formed tags, fixing mistakes by legitimate users
no_tags = tag_re.sub('', user_input)
# Clean up anything else by escaping
ready_for_web = cgi.escape(no_tags)
Source d'expression régulière: MarkupSafe . Leur version gère également les entités HTML, contrairement à celle rapide.
Pourquoi ne puis-je pas simplement retirer les étiquettes et les laisser?
C'est une chose de garder les gens à l' <i>italicizing</i>
écart des choses, sans laisser i
s flotter. Mais c'est une autre chose de prendre des entrées arbitraires et de les rendre complètement inoffensives. La plupart des techniques de cette page laisseront intacts des éléments comme les commentaires non fermés ( <!--
) et les crochets qui ne font pas partie des balises ( blah <<<><blah
). La version HTMLParser peut même laisser des balises complètes, si elles se trouvent dans un commentaire non fermé.
Et si votre modèle l'est {{ firstname }} {{ lastname }}
? firstname = '<a'
et lastname = 'href="http://evil.com/">'
seront laissés passer par tous les décapants de balises sur cette page (sauf @Medeiros!), car ce ne sont pas des balises complètes par eux-mêmes. Il ne suffit pas de supprimer les balises HTML normales.
Django's strip_tags
, une version améliorée (voir le titre suivant) de la réponse la plus importante à cette question, donne l'avertissement suivant:
Absolument AUCUNE garantie n'est fournie sur la chaîne résultante étant HTML sécurisée. Donc, NE marquez JAMAIS en sécurité le résultat d'un strip_tags
appel sans y échapper au préalable, par exemple avec escape()
.
Suivez leurs conseils!
Pour supprimer les balises avec HTMLParser, vous devez l'exécuter plusieurs fois.
Il est facile de contourner la première réponse à cette question.
Regardez cette chaîne ( source et discussion ):
<img<!-- --> src=x onerror=alert(1);//><!-- -->
La première fois que HTMLParser le voit, il ne peut pas dire qu'il <img...>
s'agit d'une balise. Il a l'air cassé, donc HTMLParser ne s'en débarrasse pas. Il enlève seulement le <!-- comments -->
, vous laissant avec
<img src=x onerror=alert(1);//>
Ce problème a été divulgué au projet Django en mars 2014. Leur ancien strip_tags
était essentiellement le même que la première réponse à cette question. Leur nouvelle version l' exécute essentiellement en boucle jusqu'à ce que la relancer ne change pas la chaîne:
# _strip_once runs HTMLParser once, pulling out just the text of all the nodes.
def strip_tags(value):
"""Returns the given HTML with all tags stripped."""
# Note: in typical case this loop executes _strip_once once. Loop condition
# is redundant, but helps to reduce number of executions of _strip_once.
while '<' in value and '>' in value:
new_value = _strip_once(value)
if len(new_value) >= len(value):
# _strip_once was not able to detect more tags
break
value = new_value
return value
Bien sûr, rien de tout cela n'est un problème si vous échappez toujours au résultat de strip_tags()
.
Mise à jour 19 mars 2015 : il y avait un bogue dans les versions de Django avant 1.4.20, 1.6.11, 1.7.7 et 1.8c1. Ces versions pourraient entrer dans une boucle infinie dans la fonction strip_tags (). La version fixe est reproduite ci-dessus. Plus de détails ici .
Bonnes choses à copier ou à utiliser
Mon exemple de code ne gère pas les entités HTML - les versions packagées Django et MarkupSafe le font.
Mon exemple de code est tiré de l'excellente bibliothèque MarkupSafe pour la prévention des scripts intersites . C'est pratique et rapide (avec des accélérations C vers sa version native Python). Il est inclus dans Google App Engine et utilisé par Jinja2 (2.7 et plus) , Mako, Pylons, etc. Il fonctionne facilement avec les modèles Django de Django 1.7.
Les strip_tags de Django et les autres utilitaires html d'une version récente sont bons, mais je les trouve moins pratiques que MarkupSafe. Ils sont assez autonomes, vous pouvez copier ce dont vous avez besoin à partir de ce fichier .
Si vous devez supprimer presque toutes les balises, la bibliothèque Bleach est bonne. Vous pouvez lui faire appliquer des règles telles que «mes utilisateurs peuvent mettre les choses en italique, mais ils ne peuvent pas créer d'iframes».
Comprenez les propriétés de votre strip-teaseuse! Exécutez des tests fuzz dessus! Voici le code que j'ai utilisé pour faire la recherche de cette réponse.
note penaude - La question elle-même concerne l'impression sur la console, mais c'est le meilleur résultat Google pour "python strip html from string", c'est pourquoi cette réponse est à 99% sur le Web.
&
). Vous pouvez soit 1) les supprimer avec les balises (souvent indésirables et inutiles car elles sont équivalentes à du texte brut), 2) les laisser inchangées (une solution appropriée si le texte supprimé revient directement dans un contexte HTML) ou 3 ) les décoder en texte brut (si le texte supprimé va dans une base de données ou un autre contexte non HTML, ou si votre infrastructure Web effectue automatiquement l'échappement HTML du texte pour vous).