usuario233864
Básicamente, quiero usar BeautifulSoup
agarrar estrictamente el texto visible en una página web. Por ejemplo, esta página web es mi caso de prueba. Y principalmente quiero obtener el texto del cuerpo (artículo) y tal vez incluso algunos nombres de pestañas aquí y allá. Probé la sugerencia en esta pregunta SO que devuelve muchos <script>
etiquetas y comentarios html que no quiero. No puedo descifrar los argumentos que necesito para la función. findAll()
con el fin de obtener sólo los textos visibles en una página web.
Entonces, ¿cómo debo encontrar todo el texto visible excluyendo scripts, comentarios, css, etc.?
jbochi
Prueba esto:
from bs4 import BeautifulSoup
from bs4.element import Comment
import urllib.request
def tag_visible(element):
if element.parent.name in ['style', 'script', 'head', 'title', 'meta', '[document]']:
return False
if isinstance(element, Comment):
return False
return True
def text_from_html(body):
soup = BeautifulSoup(body, 'html.parser')
texts = soup.findAll(text=True)
visible_texts = filter(tag_visible, texts)
return u" ".join(t.strip() for t in visible_texts)
html = urllib.request.urlopen('http://www.nytimes.com/2009/12/21/us/21storm.html').read()
print(text_from_html(html))
-
+1 para
soup.findAll(text=True)
nunca supe de esa característica– Hartley Brody
12 de junio de 2012 a las 17:19
-
Para BS4 reciente (al menos) podría identificar comentarios con
isinstance(element, Comment)
en lugar de hacer coincidir con una expresión regular.– triplete
2 de octubre de 2013 a las 12:48
-
Creo que la línea 2 debería ser
soup = BeautifulSoup(html)
– jczaplew
3 de abril de 2014 a las 4:43
-
En la función visible, el elif para encontrar comentarios no parecía funcionar. Tuve que actualizarlo a
elif isinstance(element,bs4.element.Comment):
. También agregué ‘meta’ a la lista de padres.-Russ salvaje
08/04/2015 a las 19:04
-
El filtro anterior tiene mucho \n en el resultado, agregue el siguiente código para eliminar los espacios en blanco y las líneas nuevas:
elif re.match(r"[\s\r\n]+",str(element)): return False
– 夜一林风
4 de diciembre de 2015 a las 10:07
La respuesta aprobada de @jbochi no me funciona. La llamada a la función str() genera una excepción porque no puede codificar los caracteres que no son ascii en el elemento BeautifulSoup. Aquí hay una forma más sucinta de filtrar la página web de ejemplo a texto visible.
html = open('21storm.html').read()
soup = BeautifulSoup(html)
[s.extract() for s in soup(['style', 'script', '[document]', 'head', 'title'])]
visible_text = soup.getText()
-
Si
str(element)
falla con problemas de codificación, deberías probarunicode(element)
en cambio, si está utilizando Python 2.– mknaf
13 de febrero de 2016 a las 15:48
patán
import urllib
from bs4 import BeautifulSoup
url = "https://www.yahoo.com"
html = urllib.urlopen(url).read()
soup = BeautifulSoup(html)
# kill all script and style elements
for script in soup(["script", "style"]):
script.extract() # rip it out
# get text
text = soup.get_text()
# break into lines and remove leading and trailing space on each
lines = (line.strip() for line in text.splitlines())
# break multi-headlines into a line each
chunks = (phrase.strip() for line in lines for phrase in line.split(" "))
# drop blank lines
text="\n".join(chunk for chunk in chunks if chunk)
print(text.encode('utf-8'))
-
Las respuestas anteriores no me funcionaron, pero esta sí 🙂
– rjurney
5 de marzo de 2016 a las 0:59
-
Si pruebo esto en la url imfuna.com, solo devuelve 6 palabras (Imfuna Property Inventory and Inspection Apps) a pesar de que hay mucho más texto/palabras en la página… alguna idea de por qué esta respuesta no funciona para eso. URL? @patán
– el_t_test_1
22 de junio de 2017 a las 14:57
-
hay alguna manera de reemplazar
<br>
etiquetas con\n
¿caracteres de nueva línea?– 12 rombos en cuadrícula sin esquinas
13 de agosto de 2020 a las 19:46
Pablo
Respeto completamente el uso de Beautiful Soup para obtener contenido renderizado, pero puede que no sea el paquete ideal para adquirir el contenido renderizado en una página.
Tuve un problema similar para obtener contenido renderizado o el contenido visible en un navegador típico. En particular, tuve muchos casos quizás atípicos para trabajar con un ejemplo tan simple a continuación. En este caso, la etiqueta no visualizable está anidada en una etiqueta de estilo y no está visible en muchos navegadores que he comprobado. Existen otras variaciones, como definir una visualización de configuración de etiqueta de clase en ninguno. Luego, usando esta clase para el div.
<html>
<title> Title here</title>
<body>
lots of text here <p> <br>
<h1> even headings </h1>
<style type="text/css">
<div > this will not be visible </div>
</style>
</body>
</html>
Una solución publicada anteriormente es:
html = Utilities.ReadFile('simple.html')
soup = BeautifulSoup.BeautifulSoup(html)
texts = soup.findAll(text=True)
visible_texts = filter(visible, texts)
print(visible_texts)
[u'\n', u'\n', u'\n\n lots of text here ', u' ', u'\n', u' even headings ', u'\n', u' this will not be visible ', u'\n', u'\n']
Esta solución ciertamente tiene aplicaciones en muchos casos y hace el trabajo bastante bien en general, pero en el html publicado anteriormente conserva el texto que no se muestra. Después de buscar SO, aparecieron un par de soluciones aquí BeautifulSoup get_text no elimina todas las etiquetas y JavaScript y aquí renderizó HTML a texto sin formato usando Python
Probé ambas soluciones: html2text y nltk.clean_html y me sorprendieron los resultados del tiempo, así que pensé que garantizaban una respuesta para la posteridad. Por supuesto, las velocidades dependen en gran medida del contenido de los datos…
Una respuesta aquí de @Helge fue sobre el uso de nltk de todas las cosas.
import nltk
%timeit nltk.clean_html(html)
was returning 153 us per loop
Funcionó muy bien para devolver una cadena con html renderizado. Este módulo nltk fue más rápido incluso que html2text, aunque quizás html2text sea más robusto.
betterHTML = html.decode(errors="ignore")
%timeit html2text.html2text(betterHTML)
%3.09 ms per loop
diego suarez
Usando BeautifulSoup de la manera más fácil con menos código para obtener solo las cadenas, sin líneas vacías ni basura.
tag = <Parent_Tag_that_contains_the_data>
soup = BeautifulSoup(tag, 'html.parser')
for i in soup.stripped_strings:
print repr(i)
-
De lejos, la mejor y más directa respuesta, ¡gracias!
– Zhink
4 sep 2021 a las 19:16
-
Tenga en cuenta, sin embargo, que stripped_strings incluirá el título de la página que no se muestra en la página.
– Mermaldad
20 de noviembre de 2021 a las 15:10
-
Leyendo más, veo que la solución de cerveza @polor usa stripped_strings pero corrige el título de la página.
– Mermaldad
20 de noviembre de 2021 a las 15:36
Cerveza Polo
Si te preocupa el rendimiento, aquí hay otra forma más eficiente:
import re
INVISIBLE_ELEMS = ('style', 'script', 'head', 'title')
RE_SPACES = re.compile(r'\s{3,}')
def visible_texts(soup):
""" get visible text from a document """
text=" ".join([
s for s in soup.strings
if s.parent.name not in INVISIBLE_ELEMS
])
# collapse multiple spaces to two spaces.
return RE_SPACES.sub(' ', text)
soup.strings
es un iterador, y devuelve NavigableString
para que pueda verificar el nombre de la etiqueta principal directamente, sin pasar por múltiples bucles.
-
De lejos, la mejor y más directa respuesta, ¡gracias!
– Zhink
4 sep 2021 a las 19:16
-
Tenga en cuenta, sin embargo, que stripped_strings incluirá el título de la página que no se muestra en la página.
– Mermaldad
20 de noviembre de 2021 a las 15:10
-
Leyendo más, veo que la solución de cerveza @polor usa stripped_strings pero corrige el título de la página.
– Mermaldad
20 de noviembre de 2021 a las 15:36
Kirenia
Si bien, sugeriría completamente usar beautiful-soup en general, si alguien está buscando mostrar las partes visibles de un html mal formado (por ejemplo, donde solo tiene un segmento o línea de una página web) por cualquier razón, lo siguiente eliminará el contenido entre <
y >
etiquetas:
import re ## only use with malformed html - this is not efficient
def display_visible_html_using_re(text):
return(re.sub("(\<.*?\>)", "",text))
Hay una actualización para más nuevos
BeautifulSoup
Versiones 4.9.+ stackoverflow.com/a/73701993/14460824– Erizo
13 de septiembre a las 11:48