Frage

Im Grunde mag ich BeautifulSoup zu greifen streng den sichtbarer Text auf einer Webseite verwenden. Zum Beispiel diese Webseite mein Testfall ist. Und ich will in erster Linie nur den Textkörper erhalten (Artikel) und vielleicht sogar ein paar Tabnamen hier und da. Ich habe den Vorschlag versucht, in dieser SO Frage dass kehrt viele <script>-Tags und hTML-Kommentare, die ich nicht will. Ich kann die Argumente herauszufinden, ich für die Funktion benötigen findAll() bekommen nur die sichtbaren Texte auf einer Webseite.

Also, wie soll ich alle sichtbaren Text finden ohne Skripte, Kommentare, CSS etc.?

War es hilfreich?

Lösung

Versuchen Sie diese:

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

Andere Tipps

Die zugelassene Antwort von @jbochi nicht für mich arbeiten. Der str () Funktionsaufruf löst eine Ausnahme, weil es nicht die Nicht-ASCII-Zeichen im BeautifulSoup Elemente kodieren kann. Hier ist ein prägnanter Weise das Beispiel Web-Seite sichtbaren Text zu filtern.

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

Ich respektiere vollständig Schöne Suppe zu bekommen gerenderten Inhalt verwenden, aber es kann nicht das ideale Paket sein, auf einer Seite mit dem wiedergegebenen Inhalt zu erwerben.

Ich hatte ein ähnliches Problem gemacht Inhalt zu erhalten, oder den sichtbaren Inhalt in einem typischen Browser. Insbesondere hatte ich viele vielleicht atypische Fälle an der Arbeit mit einem so einfachen Beispiel unten. In diesem Fall wird der nicht darstellbare-Tag ist in einem Stil-Tag verschachtelt, und ist nicht sichtbar in vielen Browsern, dass ich überprüft haben. Andere Varianten existieren, wie eine Klasse-Tag-Einstellung Anzeige zu keinem definieren. Dann unter Verwendung dieser Klasse für die 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>

Eine Lösung gepostet oben ist:

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']

Diese Lösung hat sicherlich Anwendungen in vielen Fällen und macht den Job ganz gut im Allgemeinen aber in dem HTML-Code darüber geschrieben behält den Text, der nicht wiedergegeben wird. Nach der Suche SO ein paar Lösungen kamen hier BeautifulSoup get_text nicht alle Tags und JavaScript abzustreifen und hier Rendered HTML Klartext mit Python

Ich habe versucht, diese beiden Lösungen: html2text und nltk.clean_html und wurde von den Zeitmessungs-Ergebnissen überrascht, so dachte sie für die Nachwelt eine Antwort garantiert. Natürlich hängen die Geschwindigkeiten stark von dem Inhalt der Daten ...

Eine Antwort hier aus @Helge war über nltk aller Dinge verwenden.

import nltk

%timeit nltk.clean_html(html)
was returning 153 us per loop

Es funktionierte wirklich gut einen String mit HTML gerendert zurückzukehren. Dieses nltk Modul war sogar schneller als html2text, wenn auch vielleicht html2text robuster ist.

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

Mit BeautifulSoup der einfachste Weg, mit weniger Code nur die Saiten bekommen, ohne leere Zeilen und Mist.

tag = <Parent_Tag_that_contains_the_data>
soup = BeautifulSoup(tag, 'html.parser')

for i in soup.stripped_strings:
    print repr(i)

Wenn Sie über die Leistung kümmern, hier ist eine andere effizientere Art und Weise:

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 ist ein Iterator, und es kehrt NavigableString, so dass Sie den Tag-Namen der Eltern überprüfen können direkt, ohne mehrere Schleifen durchlaufen.

Der Titel befindet sich in einer <nyt_headline>-Tag, das innerhalb eines <h1> Tag und einem <div>-Tag mit der ID „Artikel“ verschachtelt ist.

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

Should Arbeit.

Der Artikel Körper befindet sich in einer <nyt_text>-Tag, das in einem <div>-Tag mit der ID „Article“ verschachtelt ist. Im Inneren des <nyt_text> Element, wird der Text selbst innerhalb <p> Tags enthalten. Die Bilder sind nicht in diesen <p> Tags. Es ist schwierig für mich, mit der Syntax zu experimentieren, aber ich erwarte eine Arbeits schaben zu etwa so aussehen.

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

Während ich würde ganz schlägt vor, mit schön-Suppe in der Regel, wenn jemand sucht die sichtbaren Teile eines fehlerhaften HTML angezeigt werden (zB wenn Sie nur ein Segment oder Zeile einer Web-Seite haben) für was auch immer-Grund, die folgende Inhalt zwischen < und > Tags entfernen werden:

import re   ## only use with malformed html - this is not efficient
def display_visible_html_using_re(text):             
    return(re.sub("(\<.*?\>)", "",text))
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top