【问题标题】:Python HTMLParser dividing data at &Python HTMLParser 在 & 处划分数据
【发布时间】:2012-03-31 10:28:37
【问题描述】:

我正在使用一个简单的 HTMLParser 来解析一个网页,该网页的代码总是格式正确(它是自动生成的)。它运行良好,直到它遇到一条带有“&”号的数据 - 它似乎认为这使它成为两个独立的数据并分别处理它们。 (也就是说,它调用了两次“handle_data”。)我起初认为取消转义 '&' 会解决问题,但我认为它不会。有没有人对我如何让我的解析器处理,例如“Paradise Bakery and Cafe”(即“Paradise Bakery & Café”)作为单个数据项而不是两个数据项有任何建议?

非常感谢, bsg

附:请不要告诉我我真的应该使用 BeautifulSoup。我知道。但是在这种情况下,我知道标记每次都能保证格式正确,而且我发现 HTMLParser 比 BeautifulSoup 更容​​易使用。谢谢。

我正在添加我的代码 - 谢谢!

#this class, extending HTMLParser, is written to process HTML within a <ul>. 
#There are 6 <a> elements nested within each <li>, and I need the data from the second 
#one. Whenever it encounters an <li> tag, it sets the 'is_li' flag to true and resets 
#the count of a's seen to 0; whenever it encounters an <a> tag, it increments the count
#by 1.   When handle_data is called, it checks to make sure that the data is within
#1)an li element and 2) an a element, and that the a element is the second one in that
#li (num_as == 2). If so, it adds the data to the list. 

class MyHTMLParser(HTMLParser):
pages = []
is_li = 'false'
#is_li 
num_as = 0

def _init_(self):
    HTMLParser._init_(self)
    self.pages = []
    self.is_li = 'false'
    self.num_as = 0
    self.close_a = 'false'
    sel.close_li = 'false'
    print "initialized"


def handle_starttag(self, tag, attrs):
      if tag == 'li':
          self.is_li = 'true'
          self.close_a = 'false'
          self.close_li = 'false'


      if tag == 'a' and self.is_li == 'true':
          if self.num_as < 7:
              self.num_as += 1
              self.close_a = 'false'

          else:
              self.num_as = 0
              self.is_li = 'false'

def handle_endtag(self, tag):
     if tag == 'a':
         self.close_a = 'true'

     if tag == 'li':
         self.close_li = 'true'
         self.num_as = 0

def handle_data(self, data):
    if self.is_li == 'true':
        if self.num_as == 2 and self.close_li == 'false' and self.close_a == 'false':
            print "found data",  data
            self.pages.append(data)

def get_pages(self):
    return self.pages

【问题讨论】:

    标签: python escaping html-parsing


    【解决方案1】:

    这是因为&amp;amp; 是 HTML 实体的开头。显示的&amp;amp; 应该在 HTML 中表示为&amp;amp;(尽管浏览器会显示一个&amp;amp;,后跟一个空格作为&,我相信从技术上讲这是无效的)。

    您只需要编写您的handle_data() 以适应多个调用,例如使用一个成员变量,当您看到您的开始标签时将其设置为[],并在每次调用handle_data() 时附加到然后当你看到你的结束标签时加入一个字符串。

    我在下面试了一下。我添加的关键行有一个# ***** 评论。我还冒昧地为您的标志而不是字符串使用适当的布尔值,因为它可以让代码更简洁(希望我没有搞砸)。我还将您的 __init__() 更改为 reset() 方法(以便可以重用您的解析器对象)并删除了多余的类变量。最后,我添加了handle_entityref()handle_charref() 方法来处理转义字符实体。

    class MyHTMLParser(HTMLParser):
    
        def reset(self):
            HTMLParser.reset(self)
            self.pages    = []
            self.text     = []                     # *****
            self.is_li    = False
            self.num_as   = 0
            self.close_a  = False
            self.close_li = False
    
        def handle_starttag(self, tag, attrs):
              if tag == 'li':
                  self.is_li    = True
                  self.close_a  = False
                  self.close_li = False
    
              if tag == 'a' and self.is_li:
                  if self.num_as < 7:
                      self.num_as += 1
                      self.close_a = False
                  else:
                      self.num_as = 0
                      self.is_li = False
    
        def handle_endtag(self, tag):
             if tag == 'a':
                 self.close_a  = True
             if tag == 'li':
                 self.close_li = True
                 self.num_as   = 0
                 self.pages.append("".join(self.text))      # *****
                 self.text = []                             # *****
    
        def handle_data(self, data):
            if self.is_li:
                if self.num_as == 2 and not self.close_li and not self.close_a:
                    print "found data",  data
                    self.text.append(data)              # *****
    
        def handle_charref(self, ref):
            self.handle_entityref("#" + ref)
    
        def handle_entityref(self, ref):
            self.handle_data(self.unescape("&%s;" % ref))
    
        def get_pages(self):
            return self.pages
    

    基本思想是,不是在每次调用handle_data() 时附加到self.pages,而是附加到self.text。然后你会发现每个文本元素都会发生一次其他事件(我选择当你看到 &lt;/li&gt; 标签但它可能是当你看到 &lt;/a&gt; 时,如果没有看到你的一些数据,我真的无法判断) ,合并这些文本,并将 that 附加到pages

    希望这能让您了解我正在谈论的方法,即使我发布的确切代码不适合您。

    【讨论】:

    • 效果很好 - 非常感谢!感谢您清理我的代码 - 不管你信不信,我自学的 Python 技能不知何故不包括正确的布尔运算方法。
    • 它跑了???考虑到我所做的所有更改并且我实际上并没有尝试过,这还不错。 :-)
    【解决方案2】:

    取消转义&amp;amp; 会导致&amp;amp; 的奇怪行为。我创建了一个类,它不会在&amp;amp; 实体处将数据拆分成块。你可以找到它HERE

    【讨论】:

      猜你喜欢
      • 2010-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-16
      • 2015-02-04
      • 1970-01-01
      • 2012-06-19
      相关资源
      最近更新 更多