2010-04-06 9 views
8

quiero la siguiente funcionalidad.etiquetas de tira python

input : this is test <b> bold text </b> normal text 
expected output: this is test normal text 

es decir, eliminar el contenido de la etiqueta especificada

+0

¿Es necesario esto para cualquier etiqueta o simplemente el ejemplo dado ? –

+1

@ cb160 quiero con cualquier etiqueta. es decir, genérico – developer

+0

¿Desea que se quite todas las etiquetas o solo las que enumera? –

Respuesta

9

solución utilizando BeautifulSoup:

from BeautifulSoup import BeautifulSoup 
def removeTag(soup, tagname): 
    for tag in soup.findAll(tagname): 
     contents = tag.contents 
     parent = tag.parent 
     tag.extract() 

s = BeautifulSoup("abcd <b> btag </b> hello <d>dtag</d>") 

removeTag(s,"b") 
print s 
removeTag(s, "d") 
print s 

devuelve:

>>> 
abcd hello <d>dtag</d> 
abcd hello 
5

Con BeautifulSoup:

from BeautifulSoup import BeautifulSoup  
''.join(BeautifulSoup(page).findAll(text=True)) 

encontrar en http://www.ghastlyfop.com/blog/2008/12/strip-html-tags-from-string-python.html

+1

+1 por no usar REs en HTML –

+0

@Brain ya he probado este. pero solo elimina la etiqueta, no el contenido que contiene. – developer

+0

@ user283405. Hmm, asegúrate de usar una redacción adecuada. Supongo que lo que necesitas es eliminar el contenido de un elemento (básicamente, algo que comienza con la etiqueta de apertura y termina con la etiqueta de cierre). ¿Derecha? –

2

Pruebe con:

import re 
input = 'this is test <b> bold text </b> normal text' 
output = re.compile(r'<[^<]*?/?>').sub('', input) 
print output 
+2

Regex + HTML = incorrecto. Esencialmente HTML, ya que está (en su mayoría) anidado, no es un lenguaje regular, por lo que no puede ser analizado correctamente por expresiones regulares. Esto es SOlore: http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags –

+0

Tienes toda la razón; de todos modos funcionó para el ejemplo OP;). – systempuntoout

+1

En lo que concierne a esta pregunta, no estamos analizando el HTML (es decir, no nos importa qué partes del texto están entre las etiquetas 'abrir' y 'cerrar') y no nos importa cuán profundamente anidadas las etiquetas son, por lo que Regex es una herramienta perfecta para usar. (aunque se cae debido a caracteres '<' que no se encuentran en las etiquetas, como se señala en otras respuestas) –

3

Si Don No importa Python (aunque las expresiones regulares son bastante genéricas), puede inspirarse en Django's strip_tags filter.

Reproducido aquí para completar -

def strip_tags(value): 
    """Returns the given HTML with all tags stripped.""" 
    return re.sub(r'<[^>]*?>', '', force_unicode(value)) 

EDIT: Si está usando esto, o cualquier otra solución de expresión regular, por favor, tenga en cuenta que se permite el paso de HTML cuidadosamente diseñado (ver comentario), así como Los comentarios HTML y, por lo tanto, no deben usarse con datos que no sean de confianza. Considere utilizar algunas de las respuestas de beautifulsoup, html5lib o lxml para las entradas que no son de confianza.

+0

El filtro 'strip_tags' de Django está roto y casi inútil. Es perfectamente válido poner un carácter '>' en los valores de los atributos, y esto ni siquiera intenta manejar otras construcciones de marcado, como los comentarios. – bobince

+0

De acuerdo (He leído la loca pregunta en algún lugar de StackOverflow tratando de diseñar una expresión regular para analizar HTML :). Personalmente en mi sitio web, utilizo lxml para hacer lo mismo (y también para quitar etiquetas y atributos prohibidos). Creo que la respuesta anterior todavía tiene un uso válido cuando el rendimiento es importante, pero solo debe implementarse teniendo en cuenta esas serias limitaciones. – Sam

2

Parece que quiere HTMLParser. (html.parser en Python 3.)

from HTMLParser import HTMLParser 
from sys import stdout 
class Filter(HTMLParser): 
    def __init__(self, ignored_tags): 
     super(Filter, self).__init__() 
     self.ignorelevel = 0 
     self. ignored_tags = ignored_tags 
    def handle_starttag(self, tag, attrs): 
     if self.ignorelevel > 0: 
      self.ignorelevel += 1 
     elif tag in self.ignored_tags: 
      self.ignorelevel = 1 
     else: 
      # One of these two. Test and see. 
      stdout.write(self.get_starttag_text()) 
      #stdout.write('<' + self.get_starttag_text() + '>') 
    def handle_startendtag(self, tag, attrs): 
     if self.ignorelevel == 0 and tag not in self.ignored_tags: 
      # One of these two. Test and see. 
      stdout.write(self.get_starttag_text()) 
      #stdout.write('<' + self.get_starttag_text() + '/>') 
    def handle_endtag(self, tag): 
     if self.ignorelevel > 0: 
      self.ignorelevel -= 1 
      if self.ignorelevel > 0: 
       return 
     stdout.write('</' + tag + '>') 
    def handle_data(self, data): 
     stdout.write(data) 
    def handle_charref(self, name): 
     stdout.write('&#' + name + ';') 
    def handle_entityref(self, name): 
     stdout.write('&' + name + ';') 
    def handle_comment(self, data): 
     stdout.write('<!-- ' + data + ' -->') 
    def handle_decl(self, data): 
     stdout.write('<!' + data + '>') 
    def handle_pi(self, data): 
     stdout.write('<?' + data + '>') 
0

respuesta de Sam debe hacer lo que se quería bastante bien por lo que yo puedo decir, pero puede pagar para asegurarse de que cualquier sobrante < > caracteres se reemplazan por & lt; y & gt; respectivamente para evitar el uso indebido/HTML no válido.

Este enfoque tiene la ventaja de que puede aceptar referencias/etiquetas HTML increíblemente malformadas. BeautifulSoup también maneja las etiquetas mal formadas bastante bien, pero html5lib, sgmllib y htmllib pueden ahogarse en el código no válido, algunos más que otros si no recuerdo mal.

El siguiente código también valida & referencias HTML:

import re 
from htmlentitydefs import name2codepoint, codepoint2name 

S = '1234567890ABCDEF' 
DHex = {} 
for i in S: 
    DHex[i.lower()] = None 
    DHex[i.upper()] = None 

def IsHex(S): 
    if not S: return False 
    for i in S: 
     if i not in DHex: 
      return False 
    return True 

def UnEscape(S, LReEscape=None): 
    # Converts HTML character references into a unicode string to allow manipulation 
    # 
    # If LUnEscape is provided, then the positions of the escaped characters will be 
    # added to allow turning the result back into HTML with ReEscape below, validating 
    # the references and escaping all the rest 
    # 
    # This is needed to prevent browsers from stripping out e.g. &#32; (spaces) etc 
    re = LReEscape != None 

    LRtn = [] 
    L = S.split('&') 
    xx = 0 
    yy = 0 
    for iS in L: 
     if xx: 
      LSplit = iS.split(';') 
      if LSplit[0].lower() in name2codepoint: 
       # A character reference, e.g. '&amp;' 
       a = unichr(name2codepoint[LSplit[0].lower()]) 
       LRtn.append(a+';'.join(LSplit[1:])) 
       if re: LReEscape.append((yy, a)) 

      elif LSplit[0] and LSplit[0][0] == '#' and LSplit[0][1:].isdigit(): 
       # A character number e.g. '&#52;' 
       a = unichr(int(LSplit[0][1:])) 
       LRtn.append(a+';'.join(LSplit[1:])) 
       if re: LReEscape.append((yy, a)) 

      elif LSplit[0] and LSplit[0][0] == '#' and LSplit[0][1:2].lower() == 'x' and IsHex(LSplit[0][2:]): 
       # A hexadecimal encoded character 
       a = unichr(int(LSplit[0][2:].lower(), 16)) # Hex -> base 16 
       LRtn.append(a+';'.join(LSplit[1:])) 
       if re: LReEscape.append((yy, a)) 

      else: LRtn.append('&%s' % ';'.join(LSplit)) 
     else: LRtn.append(iS) 
     xx += 1 
     yy += len(LRtn[-1]) 
    return ''.join(LRtn) 

def ReEscape(LReEscape, S, EscFn): 
    # Re-escapes the output of UnEscape to HTML, ensuring e.g. &#32; 
    # is turned back again and isn't stripped at a browser level 
    L = [] 
    prev = 0 
    for x, c in LReEscape: 
     if x != prev: 
      L.append(EscFn(S[prev:x])) 

     o = ord(c) 
     if o in codepoint2name: 
      L.append('&%s;' % codepoint2name[o]) 
     else: L.append('&#%s;' % o) 
     prev = x+len(c) 
    L.append(EscFn(S[prev:])) 
    return ''.join(L) 

def escape(value): 
    # Escape left over <>& tags 
    value = value.replace('&', '&amp;') 
    value = value.replace('>', '&gt;') 
    value = value.replace('<', '&lt;') 
    return value 

def strip_tags(value): 
    # Strip HTML tags 
    value = re.sub(r'<[^>]*?>', '', value) 
    print 'No Tags:', value 

    # Validate & references 
    LReEscape = [] 
    value = UnEscape(value, LReEscape) 
    value = ReEscape(LReEscape, value, EscFn=escape) 
    print 'References Validated:', value 
    return value 

if __name__ == '__main__': 
    # Outputs: 
    # No Tags: this is test bold text normal text >< &blah &amp; &amp 
    # References Validated: this is test bold text normal text &gt;&lt; &amp;blah &amp; &amp; 
    strip_tags('this is test <b> bold text </b> normal text >< &blah &amp; &amp') 
0

Este código está trabajando tomadas de mi proyecto Supybot, por lo que está bastante bien probado:

class HtmlToText(sgmllib.SGMLParser): 
    """Taken from some eff-bot code on c.l.p.""" 
    entitydefs = htmlentitydefs.entitydefs.copy() 
    entitydefs['nbsp'] = ' ' 
    def __init__(self, tagReplace=' '): 
     self.data = [] 
     self.tagReplace = tagReplace 
     sgmllib.SGMLParser.__init__(self) 

    def unknown_starttag(self, tag, attr): 
     self.data.append(self.tagReplace) 

    def unknown_endtag(self, tag): 
     self.data.append(self.tagReplace) 

    def handle_data(self, data): 
     self.data.append(data) 

    def getText(self): 
     text = ''.join(self.data).strip() 
     return normalizeWhitespace(text) 

def htmlToText(s, tagReplace=' '): 
    """Turns HTML into text. tagReplace is a string to replace HTML tags with. 
    """ 
    x = HtmlToText(tagReplace) 
    x.feed(s) 
    return x.getText()

Como señala la cadena de documentación, se originó con Fredrik Lundh, no yo.Como se suele decir, grandes autores roban :)

0

utilizar el módulo webob.exc:

from webob.exc import strip_tags 

y luego usarlo:

print strip_tags('a<br/>b') 
>> ab 
Cuestiones relacionadas