Python:unescape特殊字符,不分割数据

时间:2014-01-02 03:53:39

标签: python html special-characters

我制作了一个简单的HTML解析器,它基本上是来自文档的直接复制。我无法在没有将数据分成多个块的情况下对特殊字符进行转义。

这是我的代码,其中有一个简单的例子:

from HTMLParser import HTMLParser

class MyHTMLParser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.data = []

    def handle_starttag(self, tag, attrs):
        #print (tag,attrs)
        pass

    def handle_endtag(self, tag):
        #print (tag)
        pass

    def handle_data(self, data):
        self.data.append(data)

    def handle_charref(self, ref):
        self.handle_entityref("#" + ref)

    def handle_entityref(self, ref):
        self.handle_data(self.unescape("&%s;" % ref))



n = "<strong>I &lt;3s U &amp; you luvz me</strong>"


parser = MyHTMLParser()
parser.feed(n)
parser.close()
data = parser.data
print(data)

问题是这会返回5个独立的数据位

['I ', u'<', '3s U ', u'&', ' you luvz me']

我想要的是单个字符串:

['I <3s U & you luvz me']

由于 JP

3 个答案:

答案 0 :(得分:3)

使用str.join加入字符串列表:

>>> ''.join(['I ', u'<', '3s U ', u'&', ' you luvz me'])
u'I <3s U & you luvz me'

或者,您可以使用外部库,例如lxml

>>> import lxml.html
>>> n = "<strong>I &lt;3s U &amp; you luvz me</strong>"
>>> root = lxml.html.fromstring(n)
>>> root.text_content()
'I <3s U & you luvz me'

答案 1 :(得分:1)

请记住,HTMLParser的目的是让您从输入构建文档树。如果您根本不关心文档的结构,那么str.join解决方案@falsetru就可以了。您可以确定将过滤掉所有元素标记和注释。

但是,如果确实需要更复杂场景的结构,则必须构建文档树。这里有handle_starttaghandle_endtag方法。

首先,我们需要一个可以保存一些信息的基本树。

class Element:
    def __init__(self, parent, tag, attrs=None):
        self.parent = parent
        self.tag = tag
        self.children = []
        self.attrs = attrs or []
        self.data = ''

现在,您需要让HTMLParser在每个handle_starttag上创建一个新节点,并在每个handle_endtag上向上移动树。我们还将解析后的数据传递给当前节点,而不是将其保存在解析器中。

class MyHTMLParser(HTMLParser):
    def __init__(self):
        super().__init__()
        self.root = Element(NONE, '__DOCROOT__') # Special root node for us
        self.current = self.root

    def handle_starttag(self, tag, attrs):
        newel = Element(self.current tag, attrs)
        self.current.children.append(newel)
        self.current = newel

    def handle_endtag(self, tag):
        self.current = self.current.parent

    def handle_data(self, data):
        self.current.data += data

    def handle_charref(self, ref): # No changes here
        self.handle_entityref('#' + ref)

    def handle_entityref(self, ref): # No changes here either
        self.handle_data(self.unescape("&%s" % ref))

现在,您可以访问MyHTMLParser.root上的树,以便根据需要从任何元素中获取数据。例如

n = '<strong>I &lt;3s U &amp; you luvz me</strong>'
p = MyHTMLParser()
p.feed(n)
p.close()

def print_tree(node, indent=0):
    print('    ' * indent + node.tag)
    print('    ' * indent + '  ' + node.data)
    for c in node.children:
        print_tree(c, indent + 1)

print_tree(p.root)

这会给你

__DOCROOT__

    strong
      I <3s U & you luvz me

相反,如果您解析n = <html><head><title>Test</title></head><body><h1>I &lt;3s U &amp; you luvz me</h1></body></html>,您就会得到。

__DOCROOT__

    html

        head

            title
              Test
        body

            h1
              I <3s U & you luvz me

接下来是使树构建健壮并处理不匹配或隐式结束标记等情况。您还需要在find('tag')上添加一些不错的Element类似方法来遍历树。做得好,你就做了下一个BeautifulSoup

答案 2 :(得分:1)

您可以参考此answer

并根据需要修改html_to_text功能。

from HTMLParser import HTMLParser
n = "<strong>I &lt;3s U &amp; you luvz me</strong>"

class MLStripper(HTMLParser):
    def __init__(self):
        self.reset()
        self.fed = []
    def handle_data(self, d):
        self.fed.append(d)
    def handle_entityref(self, name):
        self.fed.append('&%s;' % name)
    def get_data(self):
        return ''.join(self.fed)

def html_to_text(html):
    s = MLStripper()
    s.feed(html)
    return HTMLParser().unescape(s.get_data())

print html_to_text(n)

输出:

I <3s U & you luvz me