2010-11-15 75 views
4

針對Python regular expression我試着用HTMLParser實現一個HTML解析器:在使用Python的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將代碼點作爲參數傳遞,而不是x6c72作爲字符串。
  • 爲什麼handle_charref的默認實現不會使用適當的字符串調用handle_data
  • 爲什麼沒有實用的handle_entityref實現我可以打電話?它可以被命名爲handle_entityref_HTML4,它將查找HTML 4中定義的實體,然後在其上調用handle_data

如果提供了該API,編寫自定義HTML解析器會容易得多。那麼我的誤解在哪裏?

+1

如果您閱讀上一個問題的答案,爲什麼不使用BeautifulSoup? HTML解析器可以解析常規無聊的HTML,但是這與實際上可以使用正則表達式處理的相同的HTML(因爲它實際上是常規的)。它不處理高級功能或任何不符合要求的內容,而BeautifulSoup具有非常好的API。 – 2010-11-15 08:45:27

回答

1

嗯,我傾向於認爲,HTMLParser不包括將HTML實體引用轉換爲普通ASCII和/或其他字符的代碼是一種可怕的疏忽。我認爲這是通過在Python3中完全不同的工作來彌補的。

但是,似乎我們可以寫一個相當簡單的實體處理程序是這樣的:

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行代碼中的最小值。也許,添加異常處理可能會使其行數加倍。

0

您是否需要實現自己的解析器,或者您可以創建?看看beautiful soup

+1

我知道我可以使用BeautifulSoup。我只是想知道使用HTMLParser代替它會是一個合理的理由,因爲使用它非常困難。 – 2010-11-18 00:18:27