【问题标题】:Converting pyparsing.ParseResults back to html string将 pyparsing.ParseResults 转换回 html 字符串
【发布时间】:2011-07-11 17:48:12
【问题描述】:

我是 pyparsing 的新手。
如何将类 pyparsing.ParseResults 的实例转换回 html 字符串。

例如

>>> type(gcdata)
<type 'unicode'>
>>> pat
{<"div"> SkipTo:(</"div">) </"div">}
>>> type(pat)
<class 'pyparsing.And'>
>>> 
>>> l = pat.searchString( gcdata  )
>>> l[0]
(['div', ([u'class', u'shoveler'], {}), ([u'id', u'purchaseShvl'], {}), False, u'<div class="shoveler-heading">\n    <p>Customers Who Bought This Item Also Bought</p>\n    \n', '</div>'], {'startDiv': [((['div', ([u'class', u'shoveler'], {}), ([u'id', u'purchaseShvl'], {}), False], {u'class': [(u'shoveler', 1)], 'empty': [(False, 3)], u'id': [(u'purchaseShvl', 2)]}), 0)], 'endDiv': [('</div>', 5)], u'class': [(u'shoveler', 1)], 'empty': [(False, 3)], u'id': [(u'purchaseShvl', 2)]})
>>> 
>>> type(l[0])
<class 'pyparsing.ParseResults'>
>>> 
>>> divhtml = foo (l[0])

所以,我需要这个函数 foo
有什么建议吗?

【问题讨论】:

    标签: python parsing html-parsing xml-parsing pyparsing


    【解决方案1】:

    这是makeHTMLTags 返回的表达式的问题,需要进行大量额外的分组和命名,如果您只需要标签文本,则会妨碍您。

    Pyparsing 包括方法originalTextFor 来帮助解决这个问题。基于来自@samplebias 的示例代码:

    start, end = makeHTMLTags('div')
    #anchor = start + SkipTo(end).setResultsName('body') + end 
    anchor = originalTextFor(start + SkipTo(end).setResultsName('body') + end)
    

    通过将表达式包装在originalTextFor 中,所有将标记分解为其组成部分的操作都将被撤消,您只需从原始字符串中取回文本(还包括任何中间空格)。默认行为是只给你这个字符串,它具有丢失所有结果名称的不幸副作用,因此取回解析的属性值可能很麻烦。当我写originalTextFor 时,我认为需要一个字符串,并且我无法将结果名称附加到字符串。所以我在originalTextFor 中添加了一个可选参数asString,默认为True,但如果传递为False,将返回一个ParseResults,其中只包含整个匹配字符串的单个标记,加上所有匹配的结果名字。所以你仍然可以从结果中提取res.id,而res[0] 会返回整个匹配的HTML。

    其他一些cmets:

    &lt;div&gt; 是一个非常常见的标签,仅使用makeHTMLTags 返回的标签就很容易出错。它将匹配任何 div,可能还有很多你并不真正感兴趣的。如果你可以使用withAttribute 指定一些也应该匹配的属性,你可以减少不匹配的数量。你可以这样做:

    start.setParseAction(withAttribute(id="purchaseShvl"))
    

    start.setParseAction(withAttribute(**{"class":"shovelr"}))
    

    (使用 'class' 作为过滤属性可能是您最常想做的事情,但由于 'class' 也是 Python 关键字,您可以像使用 id 一样使用命名参数形式,太糟糕了。)

    最后,与&lt;div&gt; 的共同点一起是嵌套的可能性。 div 经常 嵌套在 div 中,只是普通的 SkipTo 不够聪明,无法考虑到这一点。我们在重建您发布的结果时看到了这一点:

    <div class='shovelr' id='purchaseShvl>
    <div class='shovelr-heading'>
    <p>Customers WhoBought This Item Also Bought</p>
    </div>
    

    第一个终止符 &lt;/div&gt; 结束表达式的匹配。我怀疑您可能需要扩展匹配表达式以考虑这些额外的 div,而不仅仅是简单的 SkipTo(end)。

    【讨论】:

      【解决方案2】:

      使用返回 DOM 的 HTML 解析器会好得多,例如 lxml.html,但我怀疑您这样做更多是为了学习 Pyparsing。由于您没有发布源代码的 sn-p,我进行了一些猜测并使用pyparsing.makeHTMLTags 做了一个示例,如下所示。

      import cgi
      from pyparsing import makeHTMLTags, SkipTo
      
      raw = """<body><div class="shoveler" id="purchaseShvl">
      <p>Customers who bought this item also bought</p>
      <div class="foo">
          <span class="bar">Shovel cozy</span>
          <span class="bar">Shovel rack</span>
      </div>
      </div></body>"""
      
      def foo(parseResult):
          parts = []
          for token in parseResult:
              st = '<div id="%s" class="%s">' % \
                   (cgi.escape(getattr(token, 'id')),
                   cgi.escape(getattr(token, 'class')))
              parts.append(st + token.body + token.endDiv)
          return '\n'.join(parts)
      
      start, end = makeHTMLTags('div')
      anchor = start + SkipTo(end).setResultsName('body') + end
      res = anchor.searchString(raw)
      print foo(res)
      

      【讨论】:

        猜你喜欢
        • 2020-03-01
        • 1970-01-01
        • 2014-08-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-15
        • 1970-01-01
        相关资源
        最近更新 更多