Извлечение текста из файла HTML с помощью Python

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

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

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


Связанные вопросы:

Некоторое время люди, кажется, находят мой ответ NLTK (совсем недавно) чрезвычайно полезным, поэтому вы можете подумать об изменении принятого ответа. Спасибо!

Shatu 21.10.2013 22:49

Никогда не думал, что наткнусь на вопрос, который задает автор моего любимого блога! The Endeavour!

Ryan G 30.04.2014 22:27

@Shatu Теперь, когда ваше решение больше не действует, вы можете удалить свой комментарий. Спасибо! ;)

Sнаđошƒаӽ 05.04.2016 08:38
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
263
3
406 021
32
Перейти к ответу Данный вопрос помечен как решенный

Ответы 32

Ответ принят как подходящий

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

бит это gpl 3.0, что означает, что он может быть несовместим

frog32 07.11.2012 14:35

Удивительный! его автор - RIP Аарон Шварц.

Atul Arvind 10.08.2013 11:42

Кто-нибудь нашел альтернативы html2text из-за GPL 3.0?

jontsai 05.09.2014 05:21

GPL не так плоха, как люди хотят ее видеть. Аарон знал лучше.

Steve K 13.10.2014 14:59

Я пробовал и html2text, и nltk, но у меня они не работали. В итоге я выбрал Beautiful Soup 4, который прекрасно работает (без каламбура).

Ryan Shea 30.04.2015 21:58

Ищу модуль для этого. Это то, что такое html2text?

Ecko 01.02.2016 21:31

Кажется, это больше не работает, какие-либо обновления или предложения?

David Andrei Ned 15.12.2016 13:53

Я знаю, что это (ВООБЩЕ) не то место, но я перехожу по ссылке на блог Аарона, профиль и проекты на github, и меня очень беспокоит тот факт, что о его смерти не упоминается, и она, конечно, заморожена в 2012 году, как будто время остановилось или он взял очень долгий отпуск. Очень тревожно.

JulienFr 09.09.2017 02:18

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

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

Удачи

Ссылка мертвая или испорченная.

user3956566 11.08.2018 15:42

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

from stripogram import html2text
text = html2text(your_html_string)

Чтобы установить стрипограмму, запустите sudo easy_install stripogram

Этот модуль, согласно его страница pypi, устарел: «Если у вас нет каких-либо исторических причин для использования этого пакета, я бы не советовал его использовать!»

intuited 24.07.2010 23:02

Сегодня я столкнулся с той же проблемой. Я написал очень простой анализатор 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()

Это кажется наиболее простым способом сделать это в Python (2.7), используя только модули по умолчанию. Что действительно глупо, так как это такая часто используемая вещь, и нет веской причины, почему нет парсера для этого в модуле HTMLParser по умолчанию.

Ingmar Hupp 18.08.2011 02:35

Я не думаю, что конвертирую html-символы в Unicode, верно? Например, &amp; не будет преобразован в &, верно?

speedplane 30.11.2012 12:14

Для Python 3 используйте from html.parser import HTMLParser

sebhaase 30.05.2017 14:24

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

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


Используйте НЛТК

Я потратил 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)

Он просто удаляет разметку HTML и не обрабатывает теги (например, <p> и <br/>) или объекты.

utapyngo 11.12.2011 16:04

иногда этого достаточно :)

Sharmila 12.01.2012 14:42

Я хочу проголосовать за это тысячу раз. Я застрял в аду регулярных выражений, но теперь я вижу мудрость NLTK.

BenDundee 22.02.2013 21:30

Судя по всему, clean_html больше не поддерживается: github.com/nltk/nltk/commit/…

alexanderlukanin13 22.08.2013 09:51

импортировать тяжелую библиотеку, такую ​​как nltk, для такой простой задачи было бы слишком много

richie 22.10.2013 13:38

@ alexanderlukanin13 Из источника: raise NotImplementedError ("To remove HTML markup, use BeautifulSoup's get_text() function")

Chris Arena 06.04.2014 10:34

@ChrisArena Да, хороший звонок, из-за этого я перешел на BeautifulSoup.

Ryan Shea 21.04.2015 23:08

clean_html () и clean_url () - симпатичная функция в NLTK, которая была удалена, так как BeautifulSoup лучше справляется с работой и анализирует язык разметки, см. github.com/nltk/nltk/commit/… Здесь документация BeautifulSoup: crummy.com/software/BeautifulSoup/bs4/doc

mikelowry 07.06.2020 21:16

Вместо модуля HTMLParser проверьте htmllib. Он имеет аналогичный интерфейс, но выполняет большую часть работы за вас. (Он довольно древний, поэтому не очень помогает с точки зрения избавления от javascript и css. Вы можете создать производный класс, но и добавить методы с такими именами, как start_script и end_style (подробности см. В документации python), но это сложно чтобы сделать это надежно для искаженного html.) В любом случае, вот что-то простое, которое выводит простой текст на консоль

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)

NB: HTMLError и HTMLParserError должны читать HTMLParseError. Это работает, но плохо справляется с поддержанием разрывов строк.

Dave Knight 08.04.2014 12:09

Это не совсем решение 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()

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

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

Красивый суп действительно конвертирует html-сущности. Вероятно, это ваш лучший выбор, учитывая, что HTML часто содержит ошибки и проблемы с кодировкой Unicode и html. Это код, который я использую для преобразования HTML в необработанный текст:

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

Вот версия ответа xperroni, которая немного более полная. Он пропускает разделы скриптов и стилей и переводит charref (например, & # 39;) и объекты 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)

версия python 3: gist.github.com/Crazometer/af441bc7dc7353d41390a59f20f07b51

Crazometer 15.09.2016 13:00

В get_text '.join должно быть' '.join. Там должно быть пустое место, иначе некоторые тексты сойдутся вместе.

Obinna Nnenanya 21.01.2019 00:59

Кроме того, это не будет перехватывать ВСЕ тексты, за исключением того, что вы включаете другие теги текстовых контейнеров, такие как H1, H2 ...., span и т. д. Мне пришлось настроить его для лучшего охвата.

Obinna Nnenanya 21.01.2019 14:36

В Python 3.x это можно сделать очень легко, импортировав пакеты imaplib и email. Хотя это более старый пост, но, возможно, мой ответ может помочь новичкам в этом посте.

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

Теперь вы можете распечатать переменную тела, и она будет в текстовом формате :) Если она вам подходит, было бы неплохо выбрать ее как принятый ответ.

Это ничего не перерабатывать.

Antti Haapala 03.10.2017 10:23

Это показывает вам, как извлечь часть text/plain из электронного письма, если кто-то другой поместил ее туда. Он ничего не делает для преобразования HTML в открытый текст и не делает ничего отдаленно полезного, если вы пытаетесь преобразовать HTML, скажем, с веб-сайта.

tripleee 27.11.2017 16:23

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

from urllib.request import urlopen
from bs4 import BeautifulSoup

url = "http://news.bbc.co.uk/2/hi/health/2284783.stm"
html = urlopen(url).read()
soup = BeautifulSoup(html, features = "html.parser")

# 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

Как, если мы хотим выбрать какую-то строку, только что сказано, строку №3?

hepidad 26.08.2014 23:19

Сценарий убийства, спаситель !!

Nanda 17.11.2014 05:12

Пройдя через множество ответов на stackoverflow, я чувствую, что это лучший вариант для меня. Одна из проблем, с которыми я столкнулся, заключается в том, что в некоторых случаях строки складывались вместе. Мне удалось преодолеть это, добавив разделитель в функции get_text: text = soup.get_text(separator=' ')

Joswin K J 02.09.2015 12:54

Вместо soup.get_text() я использовал soup.body.get_text(), так что я не получаю никакого текста из элемента <head>, такого как заголовок.

Sjoerd 15.01.2016 16:50

Мне нужен soup.getText ()

gogasca 16.06.2016 21:20

Как извлечь символы & nbsp;, & lt; в контенте

Ashok kumar Ganesan 09.12.2016 10:44

Для Python 3, from urllib.request import urlopen

Jacob Kalakal Joseph 19.05.2017 10:48

Это прекрасно работает! Есть ли простой способ извлечь все ссылки из HTML и сохранить их в соответствии с соответствующим текстом?

Arya 23.11.2019 01:10

Идеально, за исключением того, что не разрывает линии на <br>

VBobCat 09.01.2020 00:18

На самом деле вы можете добиться того же чистого результата без этих ручных циклов, просто используя два дополнительных стандартных параметра: soup.get_text(separator='\n', strip=True)

DemX86 16.06.2020 15:42

это кажется мучительно медленным, есть ли способ сделать это быстрее?

kodlan 30.06.2020 17:50

Для более быстрой обработки я использовал selectolax lib. Он довольно ограничен и производит вывод с дополнительными пробелами, которые мне пришлось удалить вручную. Но вроде работает намного быстрее.

kodlan 30.06.2020 19:08

Другой вариант - запустить html через текстовый веб-браузер и выгрузить его. Например (с использованием Lynx):

lynx -dump html_to_convert.html > converted_html.txt

Это можно сделать в скрипте Python следующим образом:

import subprocess

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

Он не даст вам точно только текст из файла HTML, но в зависимости от вашего варианта использования это может быть предпочтительнее вывода html2text.

Я рекомендую пакет Python под названием goose-extractor. Гусь попытается извлечь следующую информацию:

Основной текст статьи Основное изображение статьи Любые фильмы Youtube / Vimeo, встроенные в статью Мета-описание Мета-теги

Подробнее: https://pypi.python.org/pypi/goose-extractor/

Другое решение, отличное от Python: Libre Office:

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

Причина, по которой я предпочитаю этот вариант другим альтернативам, заключается в том, что каждый абзац HTML преобразуется в одну текстовую строку (без разрывов строк), что я и искал. Другие методы требуют постобработки. Lynx действительно дает хороший результат, но не совсем то, что я искал. Кроме того, Libre Office можно использовать для конвертации из всевозможных форматов ...

простым способом

import re

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

этот код находит все части html_text, начинающиеся с '<' и заканчивающиеся на '>', и заменяет все найденные пустой строкой

Я добиваюсь этого примерно так.

>>> import requests
>>> url = "http://news.bbc.co.uk/2/hi/health/2284783.stm"
>>> res = requests.get(url)
>>> text = res.text

Я использую python 3.4, и этот код у меня работает нормально.

Waqar Detho 18.10.2016 23:54

текст будет содержать теги html

Ivelin 29.11.2016 15:26

если вам нужна большая скорость и меньшая точность, вы можете использовать необработанный lxml.

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

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

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)

Чтобы избежать предупреждения, укажите парсер, который будет использовать BeautifulSoup: text = ''.join(BeautifulSoup(some_html_string, "lxml").findAll(text=True))

Floyd 06.10.2016 18:14

Вы можете использовать генератор stripped_strings, чтобы избежать чрезмерного пробела - например, clean_text = ''.join(BeautifulSoup(some_html_string, "html.parser").stripped_strings

Fraser 08.04.2018 07:53

Я бы рекомендовал ' '.join(BeautifulSoup(some_html_string, "html.parser").stripped_strings) по крайней мере с одним пробелом, в противном случае строка, такая как Please click <a href = "link">text</a> to continue, отображается как Please clicktextto continue

am70 01.03.2021 00:03

Готово, спасибо @ am70!

Floyd 01.03.2021 14:53

Ответ @PeYoTIL с использованием BeautifulSoup и удалением стиля и содержимого скрипта для меня не сработал. Я пробовал использовать decompose вместо extract, но он все равно не работал. Поэтому я создал свой собственный, который также форматирует текст с помощью тегов <p> и заменяет теги <a> ссылкой href. Также отлично справляется со ссылками внутри текста. Доступно по адресу это суть со встроенным тестовым документом.

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

Спасибо, этот ответ недооценен. Для тех из нас, кто хочет иметь чистое текстовое представление, которое больше похоже на браузер (игнорируя символы новой строки и принимая во внимание только абзацы и разрывы строк), BeautifulSoup's get_text просто не сокращает его.

jrial 17.04.2018 18:03

@jrial рад, что вы нашли его полезным, также спасибо за вклад. Для всех остальных сущность ссылки была немного улучшена. OP, похоже, намекает на инструмент, который отображает html в текст, очень похоже на текстовый браузер, такой как lynx. Это то, что пытается сделать это решение. Большинство людей вносят свой вклад только в экстракторы текста.

racitup 19.04.2018 00:37

Кто-нибудь пробовал bleach.clean(html,tags=[],strip=True) с отбеливать? это работает для меня.

Кажется, у меня тоже работает, но они не рекомендуют использовать ее для этой цели: «Эта функция ориентирована на безопасность, единственная цель которой - удалить вредоносный контент из строки, чтобы он мог отображаться как контент в Интернете. страница." -> bleach.readthedocs.io/en/latest/clean.html#bleach.clean

Loktopus 25.07.2018 23:03

установить html2text, используя

pip install html2text

потом,

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

Вот код, который я использую регулярно.

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

Надеюсь, это поможет.

Я знаю, что здесь уже есть много ответов, но я думаю, что газета3k также заслуживает упоминания. Недавно мне нужно было выполнить аналогичную задачу по извлечению текста из статей в Интернете, и эта библиотека до сих пор отлично справлялась с этой задачей в моих тестах. Он игнорирует текст, найденный в пунктах меню и боковых панелях, а также любой код JavaScript, который появляется на странице как запросы OP.

from newspaper import Article

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

Если у вас уже есть загруженные файлы HTML, вы можете сделать что-то вроде этого:

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

В нем даже есть несколько функций НЛП для обобщения тем статей:

article.nlp()
article.summary

Лучше всего у меня сработали надписи.

https://github.com/weblyzard/inscriptis

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)

Результаты действительно хорошие

вы можете извлекать только текст из HTML с BeautifulSoup

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)

У меня были хорошие результаты с Апач Тика. Его цель - извлечение метаданных и текста из содержимого, поэтому базовый синтаксический анализатор настраивается соответствующим образом из коробки.

Tika может запускаться как сервер, тривиально запускать / развертывать в контейнере Docker, а оттуда можно получить доступ через Привязки Python.

Комментарий автора LibreOffice заслуживает внимания, поскольку приложение может использовать макросы Python. Кажется, он предлагает множество преимуществ как для ответа на этот вопрос, так и для развития макро-базы LibreOffice. Если это разрешение является одноразовой реализацией, а не использоваться как часть более крупной производственной программы, открытие HTML в модуле записи и сохранение страницы в виде текста, по-видимому, решит проблемы, обсуждаемые здесь.

Путь Perl (извини, мама, я никогда не буду делать это в продакшене).

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

Это плохая практика по многим причинам, например &nbsp;

Uri Goren 21.01.2019 14:11

Да! Это так! Не делай этого здесь!

brunql 22.01.2019 15:50

Хотя многие люди упоминали об использовании регулярных выражений для удаления тегов html, есть много недостатков.

Например:

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

Следует разбирать на:

Hello world
I love you

Вот фрагмент, который я придумал, вы можете настроить его под свои нужды, и он работает как шарм.

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

Другой пример использования BeautifulSoup4 в Python 2.7.9+

включает в себя:

import urllib2
from bs4 import BeautifulSoup

Код:

def read_website_to_text(url):
    page = urllib2.urlopen(url)
    soup = BeautifulSoup(page, 'html.parser')
    for script in soup(["script", "style"]):
        script.extract() 
    text = soup.get_text()
    lines = (line.strip() for line in text.splitlines())
    chunks = (phrase.strip() for line in lines for phrase in line.split("  "))
    text = '\n'.join(chunk for chunk in chunks if chunk)
    return str(text.encode('utf-8'))

Объяснил:

Прочтите данные URL как html (используя BeautifulSoup), удалите все элементы скрипта и стиля, а также получите только текст с помощью .get_text (). Разбейте на строки и удалите начальные и конечные пробелы на каждой, затем разбейте несколько заголовков на строку каждый chunks = (фраза.strip () для строки в строках для фразы в line.split ("")). Затем, используя text = '\ n'.join, отбросьте пустые строки и, наконец, вернитесь как санкционированный utf-8.

Заметки:

  • Некоторые системы, на которых это работает, не будут работать с подключениями https: // из-за проблемы с SSL, вы можете отключить проверку, чтобы исправить эту проблему. Пример исправления: http://blog.pengyifan.com/how-to-fix-python-ssl-certificate_verify_failed/

  • Python <2.7.9 может иметь некоторые проблемы с запуском этого

  • text.encode ('utf-8') может оставлять странную кодировку, возможно, вместо этого может потребоваться просто вернуть str (text).

У меня был аналогичный вопрос, и я фактически использовал один из ответов с BeautifulSoup. Проблема была в том, что это было очень медленно. В итоге я использовал библиотеку под названием selectolax. Он довольно ограничен, но подходит для этой задачи. Единственная проблема заключалась в том, что мне приходилось вручную удалять ненужные пробелы. Но, похоже, это решение BeautifulSoup работает намного быстрее.

from selectolax.parser import HTMLParser

def get_text_selectolax(html):
    tree = HTMLParser(html)

    if tree.body is None:
        return None

    for tag in tree.css('script'):
        tag.decompose()
    for tag in tree.css('style'):
        tag.decompose()

    text = tree.body.text(separator='')
    text = " ".join(text.split()) # this will remove all the whitespaces
    return text

Другие вопросы по теме