我想使用Python从HTML文件中提取文本。我想从本质上得到相同的输出,如果我从浏览器复制文本,并将其粘贴到记事本。
我想要一些更健壮的东西,而不是使用正则表达式,正则表达式可能会在格式不佳的HTML上失败。我见过很多人推荐Beautiful Soup,但我在使用它时遇到了一些问题。首先,它会抓取不需要的文本,比如JavaScript源代码。此外,它也不解释HTML实体。例如,我会期望'在HTML源代码中转换为文本中的撇号,就像我将浏览器内容粘贴到记事本一样。
更新html2text看起来很有希望。它正确地处理HTML实体,而忽略JavaScript。然而,它并不完全生成纯文本;它产生的降价,然后必须转换成纯文本。它没有示例或文档,但代码看起来很干净。
相关问题:
在python中过滤HTML标签并解析实体
在Python中将XML/HTML实体转换为Unicode字符串
下面是xperroni回答的一个版本,它更完整一些。它跳过脚本和样式部分,并翻译charref(例如,')和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()
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 {'&':'&', "'":''', '"':'"', '<':'<', '>':'>'}.get(t)
return '<a href="%s">%s</a>' % (t, t)
return re.sub(r'https?://[^] ()"\';]+|[&\'"<>]', f, text)