相关文章推荐
登录

使用Python从HTML文件中提取文本

内容来源于 Stack Overflow,遵循 CC BY-SA 4.0 许可协议进行翻译与使用。IT领域专用引擎提供翻译支持

腾讯云小微IT领域专用引擎提供翻译支持

原文
Stack Overflow用户 修改于2017-05-23
  • 该问题已被编辑
  • 提问者: Stack Overflow用户
  • 提问时间: 2008-11-30 02:28

我想用Python从HTML文件中提取文本。我想要的输出基本上与从浏览器复制文本并将其粘贴到记事本中得到的输出相同。

我想要一些比使用正则表达式更健壮的东西,因为正则表达式在格式不佳的HTML上可能会失败。我看到很多人推荐Beautiful Soup,但我在使用它时遇到了一些问题。首先,它会拾取不需要的文本,比如JavaScript源。而且,它不能解释HTML实体。例如,我希望‘in HTML source’转换为文本中的撇号,就像我将浏览器内容粘贴到记事本中一样。

更新

看起来很有希望。它正确地处理HTML实体并忽略JavaScript。但是,它并不能准确地生成纯文本;它会生成必须转换为纯文本的markdown。它没有提供示例或文档,但代码看起来很干净。

相关问题:

过滤掉HTML标签并解析python中的实体

在Python中将XML/HTML实体转换为Unicode字符串

浏览 403 关注 0 得票数 282
  • 得票数为Stack Overflow原文数据
原文
修改于2018-06-30
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2008-11-30 03:23
得票数 165

html2text

是一个Python程序,在这方面做得很好。

修改于2018-08-16
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2008-11-30 15:46
得票数 6

PyParsing做得很好。PyParsing维基被杀了,因此这里是另一个使用PyParsing的例子(

示例链接

)。花一点时间研究pyparsing的一个原因是,他还写了一个非常简短、组织良好的O‘’Reilly简写手册,而且价格也很便宜。

话虽如此,我经常使用BeautifulSoup,处理实体问题并不难,您可以在运行BeautifulSoup之前转换它们。

祝你好运

回答于2009-09-23
得票数 8

你也可以在stripogram库中使用html2text方法。

from stripogram import html2text
text = html2text(your_html_string)

要安装stripogram,请轻松运行sudo

_

安装stripogram

回答于2010-10-21
得票数 55

我发现自己今天也面临着同样的问题。我编写了一个非常简单的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):
        parser = _DeHTMLParser()
        parser.feed(text)
        parser.close()
        return parser.text()
    except:
        print_exc(file=stderr)
        return text
def main():
    text = r'''
                Project: DeHTML
                Description:
                This small script is intended to allow conversion from HTML markup to 
                plain text.
    print(dehtml(text))
if __name__ == '__main__':
    main()
修改于2016-10-22
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2011-11-20 20:34
得票数 103

注意:

NTLK不再支持

函数

下面是原始答案,评论部分提供了替代方案。

使用

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)
操作
修改于2015-07-19
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2012-02-20 14:39
得票数 4

请查看htmllib,而不是HTMLParser模块。它有一个类似的界面,但为你做了更多的工作。(它非常古老,所以在摆脱javascript和css方面帮助不大。您可以创建一个派生类,但可以添加名称为start的方法

_

脚本和结束

_

样式(有关详细信息,请参阅python文档),但对于格式错误的html,很难可靠地做到这一点。)无论如何,这里有一些简单的方法可以将纯文本打印到控制台

from htmllib import HTMLParser, HTMLParseError
from formatter import AbstractFormatter, DumbWriter
p = HTMLParser(AbstractFormatter(DumbWriter()))
try: p.feed('hello
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)
回答于2012-05-18
得票数 4

这不是一个确切的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()
回答于2012-11-30
得票数 7

有一个用于数据挖掘的模式库。

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
操作
回答于2012-11-30
得票数 3

Beautiful确实可以转换html实体。考虑到HTML经常有buggy,并且充满了unicode和html编码问题,这可能是您最好的选择。这是我用来将html转换成原始文本的代码:

import BeautifulSoup
def getsoup(data, to_unicode=False):
    data = data.replace(" ", " ")
    # Fixes for bad markup I've seen in the wild.  Remove if not applicable.
    masssage_bad_comments = [
        (re.compile(''), lambda match: ''),
    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 ""
回答于2013-05-08
得票数 14

下面是xperroni的答案的一个版本,它更完整一些。它跳过脚本和样式部分,并转换charrefs (例如,')和HTML实体(例如,&)。

它还包括一个普通的纯文本到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()
        parser.feed(html)
        parser.close()
    except HTMLParseError:
    return parser.get_text()
def text_to_html(text):
    Convert the given text to html, wrapping what looks like URLs with  tags,
    converting newlines to 
 tags and converting confusing chars into html
    entities.
    def f(mo):
        t = mo.group()
        if len(t) == 1:
            return {'&':'&', "'":''', '"':'"', '<':'<', '>':'>'}.get(t)
        return '%s' % (t, t)
    return re.sub(r'https?://[^] ()"\';]+|[&\'"<>]', f, text)
修改于2017-05-17
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2014-02-02 08:13
得票数 1

在Python3.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

现在您可以打印主体变量,它将是明文格式:)如果它对您来说足够好,那么选择它作为可接受的答案将是很好的。

回答于2014-08-08
得票数 2

另一种选择是通过基于文本的web浏览器运行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的输出更可取。

回答于2015-11-25
得票数 4

我推荐一个名为goose-extractor Goose的Python包,它将尝试提取以下信息:

文章的主要文本文章的主要图像任何Youtube/Vimeo电影嵌入文章Meta Description Meta标签

更多信息:

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

Stack Overflow用户
回答于2015-12-11
得票数 3

另一个非python解决方案: Libre Office:

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

我更喜欢这个的原因是,每个HTML段落都会转换成一个文本行(没有换行),这正是我想要的。其他方法需要后处理。Lynx确实产生了很好的输出,但并不完全是我想要的。此外,Libre Office可以用来从各种格式转换...

回答于2016-06-02
得票数 1

以一种简单的方式

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

此代码查找html的所有部分。

_

以“<”开头并以“>”结尾的文本,并将找到的所有文本替换为空字符串

回答于2016-08-30
得票数 5

如果您需要更高的速度和更低的精确度,那么您可以使用原始的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()
操作
修改于2021-03-01
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2016-10-06 23:08
得票数 18

我知道已经有很多答案了,但最重要的是

优雅

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)
回答于2016-12-06
得票数 2

@PeYoTIL的答案是使用BeautifulSoup并删除样式和脚本内容,对我来说不起作用。我试过了,用的是

而不是

但它仍然不起作用。所以我创建了我自己的,它也使用

标记和替换

带有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
0
回答于2017-01-16
得票数 3

任何人都试过了

使用

漂白剂

什么?这对我很有效。

操作
回答于2017-04-05
得票数 4

安装

html2text

使用

pip安装html2text

然后,

>>> import html2text
>>> h = html2text.HTML2Text()
>>> # Ignore converting links from HTML
>>> h.ignore_links = True
>>> print h.handle("Hello, world!")
Hello, world!
Stack Overflow用户
修改于2017-10-25
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2017-10-25 08:08
得票数 0

下面是我经常使用的代码。

from bs4 import BeautifulSoup
import urllib.request
def processText(webpage):
    # EMPTY LIST TO STORE PROCESSED TEXT
    proc_text = []
        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:
    return proc_text

我希望这能有所帮助。

原文
Stack Overflow用户
回答于2018-02-18
得票数 7

我知道这里已经有很多答案了,但我认为

newspaper3k

同样值得一提的是。我最近需要完成一个类似的任务,从web上的文章中提取文本,到目前为止,这个库在我的测试中完成了很好的工作。它忽略菜单项和侧边栏中的文本,以及在OP请求时出现在页面上的任何JavaScript。

from newspaper import Article
article = Article(url)
article.download()
article.parse()
article.text

如果你已经下载了HTML文件,你可以这样做:

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

它甚至有一些用于总结文章主题的NLP功能:

article.nlp()
article.summary
操作
回答于2018-04-06
得票数 3

对我来说最有效的方法是inscripts。

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)

结果真的很好

Stack Overflow用户
回答于2018-04-13
得票数 1

使用BeautifulSoup只能从HTML中提取文本

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)
Stack Overflow用户
回答于2018-05-07
得票数 2

我已经得到了很好的结果

Apache Tika

..。它的目的是从内容中提取元数据和文本,因此底层解析器相应地进行了开箱即用的调优。

Tika可以作为

服务器

在Docker容器中运行/部署非常简单,并且可以通过以下方式进行访问

Python绑定

..。

0
Stack Overflow用户
修改于2018-05-16
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2018-05-16 03:36
得票数 0

LibreOffice编写器注释具有优点,因为应用程序可以使用Python宏。它似乎提供了多种好处,既可以回答这个问题,也可以进一步加强LibreOffice的宏观基础。如果此解决方案是一次性实现,而不是用作更大的生产程序的一部分,则在writer中打开HTML并将页面另存为文本似乎可以解决此处讨论的问题。

Stack Overflow用户
修改于2019-01-22
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2019-01-22 03:30
得票数 1

虽然很多人提到使用regex来剥离html标签,但也有很多缺点。

例如:

hello worldI 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("
|||", "\n", ret, flags = re.IGNORECASE)
    ret = re.sub('<.*?>', ' ', ret, flags=re.DOTALL)
    ret = re.sub(r"  +", " ", ret)
    return ret
Stack Overflow用户
修改于2019-08-29
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2019-08-28 00:52
得票数 1

在Python 2.7.9+中使用BeautifulSoup4的另一个示例

包括:

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

解释:

以.get格式读取url数据(使用BeautifulSoup),删除所有脚本和样式元素,并使用html仅获取文本

_

text()。将多个标题拆分为几行并删除其中的前导空格和尾随空格,然后将多个标题拆分为一行each chunks = (phrase.strip() for line in line for phrase in line.split(“"))。然后使用text = '\n'.join,删除空行,最后作为认可的utf-8返回。

备注:

由于SSL问题,运行此命令的某些系统将失败,并显示https://连接,您可以关闭验证来修复该问题。示例修复:

http://blog.pengyifan.com/how-to-fix-python-ssl-certificate

_

验证

_

失败/

Python < 2.7.9在运行以下代码时可能会遇到一些问题

text.encode('utf-8')可能会留下奇怪的编码,可能只想返回字符串(文本)。

Stack Overflow用户
修改于2020-07-01
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2020-07-01 00:14
得票数 3

我有一个类似的问题,实际上我在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()
 
推荐文章