Извлечение текста из файла HTML с использованием Python - PullRequest
212 голосов
/ 30 ноября 2008

Я бы хотел извлечь текст из файла HTML, используя Python. По сути, я хочу получить такой же вывод, как если бы я скопировал текст из браузера и вставил его в блокнот.

Мне бы хотелось что-то более надежное, чем использование регулярных выражений, которые могут не работать на плохо сформированном HTML. Я видел, как многие люди рекомендуют Beautiful Soup, но у меня было несколько проблем с его использованием. С одной стороны, он поднял нежелательный текст, такой как источник JavaScript. Кроме того, он не интерпретирует HTML-сущности. Например, я ожидаю, что в исходном HTML-коде текст будет преобразован в апостроф, как если бы я вставил содержимое браузера в блокнот.

Обновление html2text выглядит многообещающе. Он правильно обрабатывает HTML-объекты и игнорирует JavaScript. Тем не менее, он точно не дает простой текст; он производит уценку, которая затем должна быть превращена в простой текст. Он не содержит примеров и документации, но код выглядит чистым.


Похожие вопросы:

Ответы [ 30 ]

118 голосов
/ 07 июля 2014

Лучший кусок кода, который я нашел для извлечения текста без получения JavaScript или ненужных вещей:

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)

Вам просто нужно установить BeautifulSoup до:

pip install beautifulsoup4
116 голосов
/ 30 ноября 2008

html2text - это программа на Python, которая неплохо справляется с этой задачей.

99 голосов
/ 20 ноября 2011

ПРИМЕЧАНИЕ: NTLK больше не поддерживает clean_html функцию

Оригинальный ответ ниже и альтернатива в комментариях.


Использование NLTK

Я потратил 4-5 часов на решение проблем с html2text. К счастью, я мог столкнуться с NLTK.
Это работает волшебно.

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)
52 голосов
/ 21 октября 2010

Сегодня я столкнулся с той же проблемой. Я написал очень простой HTML-парсер для удаления входящего содержимого всех разметок, возвращая оставшийся текст с минимальным форматированием.

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()
14 голосов
/ 07 мая 2013

Вот вариант ответа xperroni, который является немного более полным. Он пропускает разделы скриптов и стилей и переводит символы charrefs (например, ') и HTML (например, & amp;).

Он также включает в себя тривиальный обратный преобразователь простого текста в HTML.

"""
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)
8 голосов
/ 06 октября 2016

Я знаю, что ответов уже много, но наиболее найденное мной решение elegent и pythonic частично описано здесь .

from bs4 import BeautifulSoup

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

Обновление

Основываясь на комментарии Фрейзера, вот более элегантное решение:

from bs4 import BeautifulSoup

clean_text = ''.join(BeautifulSoup(some_html_string, "html.parser").stripped_strings)
8 голосов
/ 23 сентября 2009

Вы также можете использовать метод html2text в библиотеке стрипограмм.

from stripogram import html2text
text = html2text(your_html_string)

Для установки стрипограммы запустите sudo easy_install stripogram

7 голосов
/ 29 ноября 2012

Существует библиотека шаблонов для интеллектуального анализа данных.

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

Вы даже можете решить, какие теги оставить:

s = URL('http://www.clips.ua.ac.be').download()
s = plaintext(s, keep={'h1':[], 'h2':[], 'strong':[], 'a':['href']})
print s
6 голосов
/ 30 ноября 2008

PyParsing делает отличную работу. Вики PyParsing была убита, поэтому здесь есть еще одно место, где есть примеры использования PyParsing ( пример ссылки ). Одна из причин, по которой стоит потратить немного времени на pyparsing, заключается в том, что он также написал очень краткое, очень хорошо организованное руководство по сокращенному использованию O'Reilly, которое также недорогое.

Сказав это, я часто использую BeautifulSoup, и не так уж сложно разобраться с проблемами сущностей, вы можете конвертировать их до запуска BeautifulSoup.

Гудлак

4 голосов
/ 18 мая 2012

Это не совсем решение Python, но оно преобразует текст, сгенерированный Javascript, в текст, что я считаю важным (например, google.com). Ссылки браузера (не Lynx) имеют движок Javascript и преобразуют источник в текст с параметром -dump.

Так что вы можете сделать что-то вроде:

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