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

lxml.htmlのようにDOMを返す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 に答える
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になるオプションのパラメーターを追加しましたasStringが、Falseとして渡された場合、一致した文字列全体の1つのトークンと、一致したすべての結果名originalTextForを含むParseResultsが返されます。だからあなたはまだ抽出することができますres.id結果から、res[0]一致したHTML全体が返されます。

他のいくつかのコメント:

<div>は非常に一般的なタグであり、によって返されたタグだけを使用すると、エラーで簡単に一致しますmakeHTMLTagsこれはどのdivにも一致し、おそらくあまり興味のない多くの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>は、式の一致を終了します。単なるSkipTo(end)ではなく、これらの追加のdivを考慮に入れるために、一致する式を拡張する必要があるのではないかと思います。

于 2011-03-10T13:08:35.670 に答える