BeautifulSoup Grab Visible página web de texto

Básicamente, quiero usar BeautifulSoup para capturar estrictamente el texto visible en una página web. Por ejemplo, esta página web es mi caso de prueba. Y principalmente quiero solo obtener el texto del cuerpo (artículo) y tal vez incluso algunos nombres de tabs aquí y allá. He intentado la sugerencia en esta pregunta SO que devuelve muchas tags y comentarios html que no deseo. No puedo entender los argumentos que necesito para la función findAll() con el fin de obtener los textos visibles en una página web.

Entonces, ¿cómo debería encontrar todo el texto visible excluyendo scripts, comentarios, css, etc.?

Related of "BeautifulSoup Grab Visible página web de texto"

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)) 

La respuesta aprobada de @jbochi no funciona para mí. 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. Esta es una forma más sucinta de filtrar la página web de ejemplo para el 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() 
 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')) 

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. Entonces usando esta clase para el div.

   Title here  lots of text here 


even headings

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 representa. Después de buscar SO, un par de soluciones surgieron aquí. BeautifulSoup get_text no elimina todas las tags y JavaScript y aquí procesó HTML a texto sin formato utilizando Python

Probé ambas soluciones: html2text y nltk.clean_html y me sorprendieron los resultados de los tiempos, por lo que pensé que justificaban una respuesta para la posteridad. Por supuesto, las velocidades dependen mucho 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 era más rápido que incluso html2text, aunque quizás html2text es más robusto.

 betterHTML = html.decode(errors='ignore') %timeit html2text.html2text(betterHTML) %3.09 ms per loop 

Usando BeautifulSoup de la manera más fácil con menos código para obtener las cadenas, sin líneas vacías ni basura.

 tag =  soup = BeautifulSoup(tag, 'html.parser') for i in soup.stripped_strings: print repr(i) 

El título está dentro de una etiqueta , que está anidada dentro de una etiqueta

y una etiqueta

con id “artículo”.

 soup.findAll('nyt_headline', limit=1) 

Deberia trabajar.

El cuerpo del artículo está dentro de una etiqueta , que está anidada dentro de una etiqueta

con id “articleBody”. Dentro del elemento , el texto en sí está contenido dentro de las tags

. Las imágenes no están dentro de esas tags

. Es difícil para mí experimentar con la syntax, pero espero que un raspón en funcionamiento se vea algo así.

 text = soup.findAll('nyt_text', limit=1)[0] text.findAll('p') 

Si bien, sugeriría por completo que utilice la sopa hermosa en general, si alguien está buscando mostrar las partes visibles de un html con formato incorrecto (por ejemplo, donde tiene solo un segmento o una línea de una página web) por cualquier motivo, las siguientes eliminará el contenido entre las tags < y > :

 import re ## only use with malformed html - this is not efficient def display_visible_html_using_re(text): return(re.sub("(\<.*?\>)", "",text)) 

Si te importa 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 del padre directamente, sin pasar por varios bucles.