Frage

Ich möchte den Text mit Python aus einer HTML-Datei extrahieren.Ich möchte im Wesentlichen die gleiche Ausgabe, die ich erhalten würde, wenn ich den Text aus einem Browser kopieren und in den Editor einfügen würde.

Ich hätte gerne etwas Robusteres als die Verwendung regulärer Ausdrücke, die bei schlecht geformtem HTML möglicherweise fehlschlagen.Ich habe gesehen, dass viele Leute Beautiful Soup empfohlen haben, aber ich hatte ein paar Probleme bei der Verwendung.Zum einen wurde unerwünschter Text erfasst, beispielsweise aus der JavaScript-Quelle.Außerdem wurden keine HTML-Entitäten interpretiert.Ich würde zum Beispiel erwarten:in der HTML-Quelle, um sie in ein Apostroph im Text umzuwandeln, so als ob ich den Browserinhalt in den Editor eingefügt hätte.

Aktualisieren html2text sieht vielversprechend aus.Es verarbeitet HTML-Entitäten korrekt und ignoriert JavaScript.Es wird jedoch nicht unbedingt Klartext erzeugt;Es entsteht ein Markdown, der dann in Klartext umgewandelt werden müsste.Es enthält keine Beispiele oder Dokumentation, aber der Code sieht sauber aus.


Verwandte Fragen:

War es hilfreich?

Lösung

html2text ist ein Python -Programm, das dabei ziemlich gute Arbeit leistet.

Andere Tipps

Das beste Stück Code, den ich zum Extrahieren von Text gefunden habe, ohne JavaScript zu erhalten oder nicht um Dinge zu wollen:

import urllib
from bs4 import BeautifulSoup

url = "http://news.bbc.co.uk/2/hi/health/2284783.stm"
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)

Sie müssen nur BeautifulSoup installieren:

pip install beautifulsoup4

HINWEIS: NTLK unterstützt nicht mehr clean_html Funktion

Originale Antwort unten und eine Alternative in den Kommentaren.


Verwenden NLTK

Ich habe meine 4-5 Stunden verschwendet, um die Probleme mit HTML2Text zu beheben. Zum Glück konnte ich NLTK begegnen.
Es funktioniert magisch.

import nltk   
from urllib import urlopen

url = "http://news.bbc.co.uk/2/hi/health/2284783.stm"    
html = urlopen(url).read()    
raw = nltk.clean_html(html)  
print(raw)

Ich habe mich heute mit dem gleichen Problem konfrontiert. Ich habe einen sehr einfachen HTML -Parser geschrieben, um eingehende Inhalte aller Markups zu streifen und den verbleibenden Text mit nur einem Minimum an Formatierung zurückzugeben.

from HTMLParser import HTMLParser
from re import sub
from sys import stderr
from traceback import print_exc

class _DeHTMLParser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.__text = []

    def handle_data(self, data):
        text = data.strip()
        if len(text) > 0:
            text = sub('[ \t\r\n]+', ' ', text)
            self.__text.append(text + ' ')

    def handle_starttag(self, tag, attrs):
        if tag == 'p':
            self.__text.append('\n\n')
        elif tag == 'br':
            self.__text.append('\n')

    def handle_startendtag(self, tag, attrs):
        if tag == 'br':
            self.__text.append('\n\n')

    def text(self):
        return ''.join(self.__text).strip()


def dehtml(text):
    try:
        parser = _DeHTMLParser()
        parser.feed(text)
        parser.close()
        return parser.text()
    except:
        print_exc(file=stderr)
        return text


def main():
    text = r'''
        <html>
            <body>
                <b>Project:</b> DeHTML<br>
                <b>Description</b>:<br>
                This small script is intended to allow conversion from HTML markup to 
                plain text.
            </body>
        </html>
    '''
    print(dehtml(text))


if __name__ == '__main__':
    main()

Hier ist eine Version von Xperronis Antwort, die etwas vollständiger ist. Es überspringt Skript- und Stilabschnitte und übersetzt Charrefs (z. B. ') und HTML -Entitäten (z. B. &).

Es enthält auch einen trivialen Inverse-Konverter mit Ebenen.

"""
HTML <-> text conversions.
"""
from HTMLParser import HTMLParser, HTMLParseError
from htmlentitydefs import name2codepoint
import re

class _HTMLToText(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self._buf = []
        self.hide_output = False

    def handle_starttag(self, tag, attrs):
        if tag in ('p', 'br') and not self.hide_output:
            self._buf.append('\n')
        elif tag in ('script', 'style'):
            self.hide_output = True

    def handle_startendtag(self, tag, attrs):
        if tag == 'br':
            self._buf.append('\n')

    def handle_endtag(self, tag):
        if tag == 'p':
            self._buf.append('\n')
        elif tag in ('script', 'style'):
            self.hide_output = False

    def handle_data(self, text):
        if text and not self.hide_output:
            self._buf.append(re.sub(r'\s+', ' ', text))

    def handle_entityref(self, name):
        if name in name2codepoint and not self.hide_output:
            c = unichr(name2codepoint[name])
            self._buf.append(c)

    def handle_charref(self, name):
        if not self.hide_output:
            n = int(name[1:], 16) if name.startswith('x') else int(name)
            self._buf.append(unichr(n))

    def get_text(self):
        return re.sub(r' +', ' ', ''.join(self._buf))

def html_to_text(html):
    """
    Given a piece of HTML, return the plain text it contains.
    This handles entities and char refs, but not javascript and stylesheets.
    """
    parser = _HTMLToText()
    try:
        parser.feed(html)
        parser.close()
    except HTMLParseError:
        pass
    return parser.get_text()

def text_to_html(text):
    """
    Convert the given text to html, wrapping what looks like URLs with <a> tags,
    converting newlines to <br> tags and converting confusing chars into html
    entities.
    """
    def f(mo):
        t = mo.group()
        if len(t) == 1:
            return {'&':'&amp;', "'":'&#39;', '"':'&quot;', '<':'&lt;', '>':'&gt;'}.get(t)
        return '<a href="%s">%s</a>' % (t, t)
    return re.sub(r'https?://[^] ()"\';]+|[&\'"<>]', f, text)

Sie können auch die HTML2Text -Methode in der Stripogrammbibliothek verwenden.

from stripogram import html2text
text = html2text(your_html_string)

So installieren Sie das Stripogramm sudo easy_install stripogramm

Ich weiß, dass es bereits viele Antworten gibt, aber am meisten elegent und pythonisch Lösung, die ich gefunden habe, wird teilweise beschrieben, hier.

from bs4 import BeautifulSoup

text = ''.join(BeautifulSoup(some_html_string, "html.parser").findAll(text=True))

Aktualisieren

Basierend auf Frasers Kommentar ist hier eine elegantere Lösung:

from bs4 import BeautifulSoup

clean_text = ''.join(BeautifulSoup(some_html_string, "html.parser").stripped_strings)

Es gibt eine Musterbibliothek für Data Mining.

http://www.clips.ua.ac.be/pages/pattern-web

Sie können sogar entscheiden, welche Tags Sie behalten möchten:

s = URL('http://www.clips.ua.ac.be').download()
s = plaintext(s, keep={'h1':[], 'h2':[], 'strong':[], 'a':['href']})
print s

Pyparsing macht einen tollen Job. Das Pyparsing -Wiki wurde getötet, also ist hier ein weiterer Ort, an dem Beispiele für die Verwendung von PyParsing vorhanden sind (Beispiel Link). Ein Grund für ein wenig Zeit mit Pyparsing ist, dass er auch ein sehr kurzes, sehr gut organisiertes O'Reilly Short Cut -Handbuch geschrieben hat, das ebenfalls günstig ist.

Trotzdem benutze ich eine Menge wunderschön und es ist nicht so schwer, mit den Problemen mit den Unternehmen umzugehen. Sie können sie konvertieren, bevor Sie eine schöne Gruppe betreiben.

Viel Glück

Dies ist keine Python -Lösung, aber es wird Text JavaScript in Text umwandeln, was meiner Meinung nach wichtig ist (z. B. Google.com). Die Browser -Links (nicht Lynx) verfügen über eine JavaScript -Engine und wandeln Quelle in Text mit der Option -dump -Option um.

Sie könnten also so etwas tun wie:

fname = os.tmpnam()
fname.write(html_source)
proc = subprocess.Popen(['links', '-dump', fname], 
                        stdout=subprocess.PIPE,
                        stderr=open('/dev/null','w'))
text = proc.stdout.read()

Anstelle des HTMLParser -Moduls finden Sie HTMLLIB. Es hat eine ähnliche Schnittstelle, leistet aber mehr von der Arbeit für Sie. (Es ist ziemlich alt, daher ist es nicht viel Hilfe, JavaScript und CSS loszuwerden. Sie könnten eine abgeleitete Klasse erstellen, aber Methoden mit Namen wie start_script und end_style hinzufügen (siehe Python -Dokumente für Details), aber es ist schwer Um dies zuverlässig für missgebildete HTML zu tun.) Wie auch immer

from htmllib import HTMLParser, HTMLParseError
from formatter import AbstractFormatter, DumbWriter
p = HTMLParser(AbstractFormatter(DumbWriter()))
try: p.feed('hello<br>there'); p.close() #calling close is not usually needed, but let's play it safe
except HTMLParseError: print ':(' #the html is badly malformed (or you found a bug)

Wenn Sie mehr Geschwindigkeit und weniger Genauigkeit benötigen, können Sie RAW LXML verwenden.

import lxml.html as lh
from lxml.html.clean import clean_html

def lxml_to_text(html):
    doc = lh.fromstring(html)
    doc = clean_html(doc)
    return doc.text_content()

Installieren html2text Verwendung

PIP Installieren Sie HTML2Text

dann,

>>> import html2text
>>>
>>> h = html2text.HTML2Text()
>>> # Ignore converting links from HTML
>>> h.ignore_links = True
>>> print h.handle("<p>Hello, <a href='http://earth.google.com/'>world</a>!")
Hello, world!

Schöne Suppe konvertieren HTML -Entitäten. Es ist wahrscheinlich die beste Wahl, wenn man bedenkt, dass HTML oft fehlerhaft und mit Unicode- und HTML -Codierungsproblemen gefüllt ist. Dies ist der Code, mit dem ich HTML in Rohtext konvertieren:

import BeautifulSoup
def getsoup(data, to_unicode=False):
    data = data.replace("&nbsp;", " ")
    # Fixes for bad markup I've seen in the wild.  Remove if not applicable.
    masssage_bad_comments = [
        (re.compile('<!-([^-])'), lambda match: '<!--' + match.group(1)),
        (re.compile('<!WWWAnswer T[=\w\d\s]*>'), lambda match: '<!--' + match.group(0) + '-->'),
    ]
    myNewMassage = copy.copy(BeautifulSoup.BeautifulSoup.MARKUP_MASSAGE)
    myNewMassage.extend(masssage_bad_comments)
    return BeautifulSoup.BeautifulSoup(data, markupMassage=myNewMassage,
        convertEntities=BeautifulSoup.BeautifulSoup.ALL_ENTITIES 
                    if to_unicode else None)

remove_html = lambda c: getsoup(c, to_unicode=True).getText(separator=u' ') if c else ""

Ich empfehle, dass ein Python-Paket namens Goose-Extractor Goose versucht, die folgenden Informationen zu extrahieren:

Haupttext eines Artikels Hauptbild des Artikel

Mehr :https://pypi.python.org/pypi/goose-extractor/

Eine andere Möglichkeit besteht darin, die HTML über einen textbasierten Webbrowser auszuführen und sie abzuwerfen. Zum Beispiel (mit Lynx):

lynx -dump html_to_convert.html > converted_html.txt

Dies kann in einem Python -Skript wie folgt erfolgen:

import subprocess

with open('converted_html.txt', 'w') as outputFile:
    subprocess.call(['lynx', '-dump', 'html_to_convert.html'], stdout=testFile)

Es gibt Ihnen nicht genau den Text aus der HTML -Datei, aber abhängig von Ihrem Anwendungsfall kann er der Ausgabe von HTML2Text vorzuziehen sein.

Eine weitere Nicht-Python-Lösung: Libre Office:

soffice --headless --invisible --convert-to txt input1.html

Der Grund, warum ich diesen einer anderen Alternativen bevorzuge, ist, dass jeder HTML -Absatz in eine einzelne Textzeile umgewandelt wird (keine Zeilenumbrüche), wonach ich gesucht habe. Andere Methoden erfordern eine Nachbearbeitung. Lynx produziert eine schöne Ausgabe, aber nicht genau das, wonach ich gesucht habe. Außerdem kann Libre Office verwendet werden, um aus allen möglichen Formaten zu konvertieren ...

Jeder hat es versucht bleach.clean(html,tags=[],strip=True) mit bleichen? Es funktioniert für mich.

Ich weiß, dass es hier schon viele Antworten gibt, aber ich denke, ich denke Zeitung3k verdient auch eine Erwähnung. Ich musste kürzlich eine ähnliche Aufgabe erledigen, den Text aus Artikeln im Web zu extrahieren, und diese Bibliothek hat dies bisher in meinen Tests hervorragende Arbeit geleistet. Es ignoriert den Text in Menüelementen und Seitenleisten sowie jedes JavaScript, das auf der Seite als OP -Anfragen angezeigt wird.

from newspaper import Article

article = Article(url)
article.download()
article.parse()
article.text

Wenn Sie bereits die HTML -Dateien herunterladen lassen, können Sie so etwas tun:

article = Article('')
article.set_html(html)
article.parse()
article.text

Es verfügt sogar über einige NLP -Funktionen, um die Artikel von Artikeln zusammenzufassen:

article.nlp()
article.summary

Ich hatte gute Ergebnisse mit Apache Tika. Sein Zweck ist die Extraktion von Metadaten und Text aus dem Inhalt. Daher ist der zugrunde liegende Parser entsprechend außerhalb der Box eingestellt.

Tika kann als ausgeführt werden Server, ist trivial, in einem Docker -Container auszuführen / bereitzustellen, und kann von dort über zugegriffen werden Python -Bindungen.

in einfacher Weise

import re

html_text = open('html_file.html').read()
text_filtered = re.sub(r'<(.*?)>', '', html_text)

Dieser Code findet alle Teile des html_text mit '<' begonnen und endet mit '>' und ersetze alle durch eine leere Zeichenfolge, die gefunden wurde

Die Antwort von @PeYoTIL mit BeautifulSoup und dem Entfernen von Stil- und Skriptinhalten hat bei mir nicht funktioniert.Ich habe es mit versucht decompose anstatt extract aber es hat immer noch nicht funktioniert.Also habe ich mein eigenes erstellt, das auch den Text mit formatiert <p> Tags und Ersetzungen <a> Tags mit dem href-Link.Bewältigt auch Links innerhalb von Texten.Verfügbar um das Wesentliche mit eingebettetem Testdokument.

from bs4 import BeautifulSoup, NavigableString

def html_to_text(html):
    "Creates a formatted text email message as a string from a rendered html template (page)"
    soup = BeautifulSoup(html, 'html.parser')
    # Ignore anything in head
    body, text = soup.body, []
    for element in body.descendants:
        # We use type and not isinstance since comments, cdata, etc are subclasses that we don't want
        if type(element) == NavigableString:
            # We use the assumption that other tags can't be inside a script or style
            if element.parent.name in ('script', 'style'):
                continue

            # remove any multiple and leading/trailing whitespace
            string = ' '.join(element.string.split())
            if string:
                if element.parent.name == 'a':
                    a_tag = element.parent
                    # replace link text with the link
                    string = a_tag['href']
                    # concatenate with any non-empty immediately previous string
                    if (    type(a_tag.previous_sibling) == NavigableString and
                            a_tag.previous_sibling.string.strip() ):
                        text[-1] = text[-1] + ' ' + string
                        continue
                elif element.previous_sibling and element.previous_sibling.name == 'a':
                    text[-1] = text[-1] + ' ' + string
                    continue
                elif element.parent.name == 'p':
                    # Add extra paragraph formatting newline
                    string = '\n' + string
                text += [string]
    doc = '\n'.join(text)
    return doc

In Python 3.x können Sie es auf eine sehr einfache Weise tun, indem Sie "IMAPLIB "- und" E -Mail "-Pakete importieren. Obwohl dies ein älterer Beitrag ist, kann meine Antwort Neuankömmlingen in diesem Beitrag helfen.

status, data = self.imap.fetch(num, '(RFC822)')
email_msg = email.message_from_bytes(data[0][1]) 
#email.message_from_string(data[0][1])

#If message is multi part we only want the text version of the body, this walks the message and gets the body.

if email_msg.is_multipart():
    for part in email_msg.walk():       
        if part.get_content_type() == "text/plain":
            body = part.get_payload(decode=True) #to control automatic email-style MIME decoding (e.g., Base64, uuencode, quoted-printable)
            body = body.decode()
        elif part.get_content_type() == "text/html":
            continue

Jetzt können Sie Körpervariable drucken und es wird im Klartextformat sein :) Wenn es gut genug für Sie ist, wäre es schön, es als akzeptierte Antwort auszuwählen.

Am besten für mich sind Inskripte.

https://github.com/weglyzard/incriptis

import urllib.request
from inscriptis import get_text

url = "http://www.informationscience.ch"
html = urllib.request.urlopen(url).read().decode('utf-8')

text = get_text(html)
print(text)

Die Ergebnisse sind wirklich gut

Sie können nur Text von HTML mit BeautifulSoup extrahieren

url = "https://www.geeksforgeeks.org/extracting-email-addresses-using-regular-expressions-python/"
con = urlopen(url).read()
soup = BeautifulSoup(con,'html.parser')
texts = soup.get_text()
print(texts)

Während viele Personen, die Regex verwendet haben, um HTML -Tags zu streifen, gibt es viele Nachteile.

zum Beispiel:

<p>hello&nbsp;world</p>I love you

Sollte analysiert werden an:

Hello world
I love you

Hier ist ein Ausschnitt

import re
import html
def html2text(htm):
    ret = html.unescape(htm)
    ret = ret.translate({
        8209: ord('-'),
        8220: ord('"'),
        8221: ord('"'),
        160: ord(' '),
    })
    ret = re.sub(r"\s", " ", ret, flags = re.MULTILINE)
    ret = re.sub("<br>|<br />|</p>|</div>|</h\d>", "\n", ret, flags = re.IGNORECASE)
    ret = re.sub('<.*?>', ' ', ret, flags=re.DOTALL)
    ret = re.sub(r"  +", " ", ret)
    return ret

Hier ist der Code, den ich regelmäßig verwende.

from bs4 import BeautifulSoup
import urllib.request


def processText(webpage):

    # EMPTY LIST TO STORE PROCESSED TEXT
    proc_text = []

    try:
        news_open = urllib.request.urlopen(webpage.group())
        news_soup = BeautifulSoup(news_open, "lxml")
        news_para = news_soup.find_all("p", text = True)

        for item in news_para:
            # SPLIT WORDS, JOIN WORDS TO REMOVE EXTRA SPACES
            para_text = (' ').join((item.text).split())

            # COMBINE LINES/PARAGRAPHS INTO A LIST
            proc_text.append(para_text)

    except urllib.error.HTTPError:
        pass

    return proc_text

Ich hoffe das hilft.

Der Kommentar von LibreOffice Writer hat verdient, da die Anwendung Python -Makros einsetzen kann. Es scheint mehrere Vorteile für die Beantwortung dieser Frage und die Förderung der Makrobasis von Libreoffice zu bieten. Wenn es sich bei dieser Auflösung um eine einmalige Implementierung handelt, anstatt als Teil eines größeren Produktionsprogramms verwendet zu werden, öffnen Sie die HTML im Schriftsteller und das Speichern der Seite, da der Text die hier diskutierten Probleme zu lösen scheint.

Perl Way (sorry Mama, ich werde es nie in der Produktion tun).

import re

def html2text(html):
    res = re.sub('<.*?>', ' ', html, flags=re.DOTALL | re.MULTILINE)
    res = re.sub('\n+', '\n', res)
    res = re.sub('\r+', '', res)
    res = re.sub('[\t ]+', ' ', res)
    res = re.sub('\t+', '\t', res)
    res = re.sub('(\n )+', '\n ', res)
    return res

Ich erreiche es so etwas.

>>> import requests
>>> url = "http://news.bbc.co.uk/2/hi/health/2284783.stm"
>>> res = requests.get(url)
>>> text = res.text
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top