代码之家  ›  专栏  ›  技术社区  ›  Roland Illig

在Python中高效地使用HTMLParser

  •  4
  • Roland Illig  · 技术社区  · 15 年前

    回应 Python regular expression 我尝试使用 HTMLParser :

    import HTMLParser
    
    class ExtractHeadings(HTMLParser.HTMLParser):
    
      def __init__(self):
        HTMLParser.HTMLParser.__init__(self)
        self.text = None
        self.headings = []
    
      def is_relevant(self, tagname):
        return tagname == 'h1' or tagname == 'h2'
    
      def handle_starttag(self, tag, attrs):
        if self.is_relevant(tag):
          self.in_heading = True
          self.text = ''
    
      def handle_endtag(self, tag):
        if self.is_relevant(tag):
          self.headings += [self.text]
          self.text = None
    
      def handle_data(self, data):
        if self.text != None:
          self.text += data
    
      def handle_charref(self, name):
        if self.text != None:
          if name[0] == 'x':
            self.text += chr(int(name[1:], 16))
          else:
            self.text += chr(int(name))
    
      def handle_entityref(self, name):
        if self.text != None:
          print 'TODO: entity %s' % name
    
    def extract_headings(text):
      parser = ExtractHeadings()
      parser.feed(text)
      return parser.headings
    
    print extract_headings('abdk3<h1>The content we need</h1>aaaaabbb<h2>The content we need2</h2>')
    print extract_headings('before<h1>&#72;e&#x6c;&#108;o</h1>after')
    

    这样做的时候,我想知道这个模块的API是坏的,还是我没有注意到一些重要的事情。我的问题是:

    • 为什么我要实施 handle_charref 一定很复杂吗?我本希望一个好的API将代码点作为参数传递,而不是 x6c 72 作为字符串。
    • 为什么 把手 呼叫 handle_data 用合适的绳子?
    • 为什么没有 handle_entityref 我可以打电话给你吗?它可以被命名为 handle_entityref_HTML4 查找HTML 4中定义的实体,然后调用 处理数据 在他们身上。

    如果提供了这个API,那么编写定制的HTML解析器会容易得多。我的误会在哪里?

    2 回复  |  直到 8 年前
        1
  •  1
  •   Jim Dennis    9 年前

    嗯,我倾向于同意,对于HTMLParser来说,不包含将HTML实体引用转换为普通ASCII和/或其他字符的代码是一个可怕的疏忽。我认为,这是补救完全不同的工作在蟒蛇3。

    不过,我们似乎可以编写一个相当简单的实体处理程序,如:

    import htmlentitydefs
    def entity2char(x):
        if x.startswith('&#x'):
            # convert from hexadecimal
            return chr(int(x[3:-1], 16))
        elif x.startswith('&#'):
            # convert from decimal
            return chr(int(x[2:-1]))
        elif x[1:-1] in htmlentitydefs.entitydefs:
            return htmlentitydefs.entitydefs[x[1:-1]]
        else:
            return x
    

    ... 不过,我们应该包装以进行进一步的输入验证,并在异常处理代码中包装整数转换。

    但这应该能处理大约10行代码中的最小值。添加异常处理可能会使其行数加倍。

        2
  •  0
  •   ceth    15 年前

    您需要实现自己的解析器还是已经创建了解析器?看看 beautiful soup .