Python将HTML转换为文本并模仿格式

12 投票
4 回答
19708 浏览
提问于 2025-04-17 20:12

我正在学习BeautifulSoup,发现了很多关于“html2text”的解决方案,但我想要的那个应该能保持格式:

<ul>
<li>One</li>
<li>Two</li>
</ul>

会变成

* One
* Two

而且

Some text
<blockquote>
More magnificent text here
</blockquote>
Final text

Some text

    More magnificent text here

Final text

我在看文档,但没有找到简单明了的内容。有谁能帮帮我吗?我也愿意尝试其他的工具,不一定非要用beautifulsoup。

4 个回答

4

Python自带的html.parser模块(在早期版本中叫HTMLParser)可以很容易地扩展,创建一个简单的翻译器,能够根据你的具体需求进行定制。这个模块允许你在解析HTML时,抓住某些事件。

由于它的简单性,你不能像使用Beautiful Soup那样在HTML树中自由导航(比如访问兄弟节点、子节点、父节点等),但对于你这种简单的情况来说,应该已经足够了。

html.parser主页

在你的情况下,你可以这样使用它,每当遇到特定类型的开始标签或结束标签时,添加适当的格式:

from html.parser import HTMLParser
from os import linesep

class MyHTMLParser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self, strict=False)
    def feed(self, in_html):
        self.output = ""
        super(MyHTMLParser, self).feed(in_html)
        return self.output
    def handle_data(self, data):
        self.output += data.strip()
    def handle_starttag(self, tag, attrs):
        if tag == 'li':
            self.output += linesep + '* '
        elif tag == 'blockquote' :
            self.output += linesep + linesep + '\t'
    def handle_endtag(self, tag):
        if tag == 'blockquote':
            self.output += linesep + linesep

parser = MyHTMLParser()
content = "<ul><li>One</li><li>Two</li></ul>"
print(linesep + "Example 1:")
print(parser.feed(content))
content = "Some text<blockquote>More magnificent text here</blockquote>Final text"
print(linesep + "Example 2:")
print(parser.feed(content))
5

我有一段代码,可以用来做一个比较简单的任务:去掉HTML标签,并在合适的地方插入换行符。也许这可以作为你的一个起点。

Python的textwrap模块可能对创建缩进的文本块很有帮助。

http://docs.python.org/2/library/textwrap.html

class HtmlTool(object):
    """
    Algorithms to process HTML.
    """
    #Regular expressions to recognize different parts of HTML. 
    #Internal style sheets or JavaScript 
    script_sheet = re.compile(r"<(script|style).*?>.*?(</\1>)", 
                              re.IGNORECASE | re.DOTALL)
    #HTML comments - can contain ">"
    comment = re.compile(r"<!--(.*?)-->", re.DOTALL) 
    #HTML tags: <any-text>
    tag = re.compile(r"<.*?>", re.DOTALL)
    #Consecutive whitespace characters
    nwhites = re.compile(r"[\s]+")
    #<p>, <div>, <br> tags and associated closing tags
    p_div = re.compile(r"</?(p|div|br).*?>", 
                       re.IGNORECASE | re.DOTALL)
    #Consecutive whitespace, but no newlines
    nspace = re.compile("[^\S\n]+", re.UNICODE)
    #At least two consecutive newlines
    n2ret = re.compile("\n\n+")
    #A return followed by a space
    retspace = re.compile("(\n )")

    #For converting HTML entities to unicode
    html_parser = HTMLParser.HTMLParser()

    @staticmethod
    def to_nice_text(html):
        """Remove all HTML tags, but produce a nicely formatted text."""
        if html is None:
            return u""
        text = unicode(html)
        text = HtmlTool.script_sheet.sub("", text)
        text = HtmlTool.comment.sub("", text)
        text = HtmlTool.nwhites.sub(" ", text)
        text = HtmlTool.p_div.sub("\n", text) #convert <p>, <div>, <br> to "\n"
        text = HtmlTool.tag.sub("", text)     #remove all tags
        text = HtmlTool.html_parser.unescape(text)
        #Get whitespace right
        text = HtmlTool.nspace.sub(" ", text)
        text = HtmlTool.retspace.sub("\n", text)
        text = HtmlTool.n2ret.sub("\n\n", text)
        text = text.strip()
        return text

代码中可能还有一些多余的正则表达式。

15

看看Aaron Swartz的html2text脚本(可以通过pip install html2text来安装)。请注意,输出结果是有效的Markdown格式。如果出于某种原因这个输出不完全符合你的需求,做一些简单的调整就能得到你问题中提到的确切输出:

In [1]: import html2text

In [2]: h1 = """<ul>
   ...: <li>One</li>
   ...: <li>Two</li>
   ...: </ul>"""

In [3]: print html2text.html2text(h1)
  * One
  * Two

In [4]: h2 = """<p>Some text
   ...: <blockquote>
   ...: More magnificent text here
   ...: </blockquote>
   ...: Final text</p>"""

In [5]: print html2text.html2text(h2)
Some text

> More magnificent text here

Final text

撰写回答