2

我是 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
有什么建议么 ?

4

2 回答 2

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,我假设一个字符串是想要的,我不能将结果名称附加到一个字符串上。所以我添加了一个默认为 True 的可选参数asStringoriginalTextFor但如果作为 False 传递,将返回一个 ParseResults,其中仅包含整个匹配字符串的单个标记,以及所有匹配的结果名称。所以你仍然可以提取res.id从结果中,whileres[0]会返回整个匹配的 HTML。

其他一些评论:

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

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

或者

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

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

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

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

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

于 2011-03-10T13:08:35.670 回答
1

使用返回 DOM 的 HTML 解析器(如lxml.html )会更好,但我怀疑您这样做更多是为了学习 Pyparsing。由于您没有发布源代码片段,因此我进行了一些猜测并使用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)
于 2011-03-09T14:29:40.003 回答