scraping how from examples python beautifulsoup

how - python beautifulsoup find element



Elimine una etiqueta con BeautifulSoup pero mantenga sus contenidos (10)

Aunque esto ya ha sido mencionado por otras personas en los comentarios, pensé en publicar una respuesta completa que mostrara cómo hacerlo con Bleach de Mozilla. Personalmente, creo que esto es mucho mejor que utilizar BeautifulSoup para esto.

import bleach html = "<b>Bad</b> <strong>Ugly</strong> <script>Evil()</script>" clean = bleach.clean(html, tags=[], strip=True) print clean # Should print: "Bad Ugly Evil()"

Actualmente tengo un código que hace algo como esto:

soup = BeautifulSoup(value) for tag in soup.findAll(True): if tag.name not in VALID_TAGS: tag.extract() soup.renderContents()

Excepto que no quiero tirar el contenido dentro de la etiqueta no válida. ¿Cómo me deshago de la etiqueta pero mantengo el contenido dentro al llamar a soup.renderContents ()?


Esta es la mejor solución sin ningún tipo de molestia ni código repetitivo para filtrar las etiquetas que mantienen el contenido. Si queremos eliminar las etiquetas secundarias dentro de la etiqueta padre y solo queremos mantener el contenido / texto, simplemente podemos hacer:

for p_tags in div_tags.find_all("p"): print(p_tags.get_text())

Eso es todo y puede ser libre con todas las etiquetas br o ib dentro de las etiquetas principales y obtener el texto limpio.


Esta es una vieja pregunta, pero solo para decir de una mejor manera de hacerlo. En primer lugar, BeautifulSoup 3 * ya no se está desarrollando, por lo que debería usar BeautifulSoup 4 *, llamado bs4 .

Además, lxml solo tiene la función que necesita: la clase Cleaner tiene el atributo remove_tags , que puede establecer en etiquetas que se eliminarán mientras se sube su contenido a la etiqueta principal.


La estrategia que utilicé es reemplazar una etiqueta con su contenido si son de tipo NavigableString y si no lo son, se repiten en ellas y reemplazan sus contenidos con NavigableString , etc. Pruebe esto:

from BeautifulSoup import BeautifulSoup, NavigableString def strip_tags(html, invalid_tags): soup = BeautifulSoup(html) for tag in soup.findAll(True): if tag.name in invalid_tags: s = "" for c in tag.contents: if not isinstance(c, NavigableString): c = strip_tags(unicode(c), invalid_tags) s += unicode(c) tag.replaceWith(s) return soup html = "<p>Good, <b>bad</b>, and <i>ug<b>l</b><u>y</u></i></p>" invalid_tags = [''b'', ''i'', ''u''] print strip_tags(html, invalid_tags)

El resultado es:

<p>Good, bad, and ugly</p>

Di esta misma respuesta en otra pregunta. Parece surgir mucho.


Las versiones actuales de la biblioteca BeautifulSoup tienen un método no documentado en objetos Tag llamado replaceWithChildren (). Entonces, podrías hacer algo como esto:

html = "<p>Good, <b>bad</b>, and <i>ug<b>l</b><u>y</u></i></p>" invalid_tags = [''b'', ''i'', ''u''] soup = BeautifulSoup(html) for tag in invalid_tags: for match in soup.findAll(tag): match.replaceWithChildren() print soup

Parece que se comporta como lo desea y es un código bastante sencillo (aunque realiza algunos pasos a través del DOM, pero esto podría optimizarse fácilmente).


Ninguna de las respuestas propuestas pareció funcionar con BeautifulSoup para mí. Aquí hay una versión que funciona con BeautifulSoup 3.2.1, y también inserta un espacio al unir contenido de diferentes etiquetas en lugar de concatenar palabras.

def strip_tags(html, whitelist=[]): """ Strip all HTML tags except for a list of whitelisted tags. """ soup = BeautifulSoup(html) for tag in soup.findAll(True): if tag.name not in whitelist: tag.append('' '') tag.replaceWithChildren() result = unicode(soup) # Clean up any repeated spaces and spaces like this: ''<a>test </a> '' result = re.sub('' +'', '' '', result) result = re.sub(r'' (<[^>]*> )'', r''/1'', result) return result.strip()

Ejemplo:

strip_tags(''<h2><a><span>test</span></a> testing</h2><p>again</p>'', [''a'']) # result: u''<a>test</a> testing again''


Probablemente tendrá que mover los hijos de la etiqueta para que sean hijos del padre de la etiqueta antes de quitar la etiqueta. ¿Es eso lo que quiere decir?

Si es así, entonces, al insertar los contenidos en el lugar correcto es complicado, algo como esto debería funcionar:

from BeautifulSoup import BeautifulSoup VALID_TAGS = ''div'', ''p'' value = ''<div><p>Hello <b>there</b> my friend!</p></div>'' soup = BeautifulSoup(value) for tag in soup.findAll(True): if tag.name not in VALID_TAGS: for i, x in enumerate(tag.parent.contents): if x == tag: break else: print "Can''t find", tag, "in", tag.parent continue for r in reversed(tag.contents): tag.parent.insert(i, r) tag.extract() print soup.renderContents()

con el valor del ejemplo, esto imprime <div><p>Hello there my friend!</p></div> como lo desee.


Tengo una solución más simple pero no sé si hay un inconveniente.

ACTUALIZACIÓN: hay un inconveniente, ver el comentario de Jesse Dhillon. Además, otra solución será usar Bleach de Mozilla en lugar de BeautifulSoup.

from BeautifulSoup import BeautifulSoup VALID_TAGS = [''div'', ''p''] value = ''<div><p>Hello <b>there</b> my friend!</p></div>'' soup = BeautifulSoup(value) for tag in soup.findAll(True): if tag.name not in VALID_TAGS: tag.replaceWith(tag.renderContents()) print soup.renderContents()

Esto también imprimirá <div><p>Hello there my friend!</p></div> como lo desee.


Use desenvolver.

Desenvolver eliminará una de las múltiples apariciones de la etiqueta y aún mantendrá los contenidos.

Ejemplo:

>> soup = BeautifulSoup(''Hi. This is a <nobr> nobr </nobr>'') >> soup <html><body><p>Hi. This is a <nobr> nobr </nobr></p></body></html> >> soup.nobr.unwrap <nobr></nobr> >> soup >> <html><body><p>Hi. This is a nobr </p></body></html>


puedes usar soup.text

.text elimina todas las etiquetas y concatenan todo el texto.