3

私は現在、少しアイデアがありません。ヒントを教えていただければ幸いです。サンプルコードの小さな断片で私の質問を説明するのがおそらく最善です。

from lxml import etree
from io import StringIO

testStr = "<b>text0<i>text1</i><ul><li>item1</li><li>item2</li></ul>text2<b/><b>sib</b>"
parser = etree.HTMLParser()
# generate html tree
htmlTree   = etree.parse(StringIO(testStr), parser)
print(etree.tostring(htmlTree, pretty_print=True).decode("utf-8"))
bElem = htmlTree.getroot().find("body/b") 
print(".text only contains the first part: "+bElem.text+ " (which makes sense in some way)")
for text in bElem.itertext():
    print(text)

出力:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
  <body>
    <b>text0<i>text1</i><ul><li>item1</li><li>item2</li></ul>text2<b/><b>sib</b></b>
  </body>
</html>

.text only contains the first part: text0 (which makes sense in some way)
text0
text1
item1
item2
text2
sib

私の質問:

"text2"直接アクセスするか、親タグにあるものだけを含むすべてのテキスト部分のリストを取得したいと思います。これまでのところitertext()、表示される のみが見つかりました"text2"

取得できる他の方法はあります"text2"か?

なぜこれが必要なのかと疑問に思われるかもしれませんitertext():

  • 要素の子で見つかったすべてのテキストを含むリストを作成します
  • ただし、別の関数で検出されたテーブルとリストを処理したい (これにより、次のようなリスト構造が作成されます:["text0 text1",["item1","item2"],"text2"]またはテーブル (1. 1 列の行、2. 2 列の行): ["1. row, 1 col",["2. row, 1. col","2. row, 2. col"]])

たぶん私は完全に間違ったアプローチを取っていますか?

4

1 に答える 1

3

必要に応じて、itertext()関数を再実装し、 の特別なハンドラーを挿入するだけです。ultable

from lxml import html

def itertext(root, handlers=dict(ul=lambda el: (list(el.itertext()),
                                                el.tail))):
    if root.text:
        yield root.text
    for el in root:
        yield from handlers.get(el.tag, itertext)(el)
    if root.tail:
        yield root.tail

print(list(itertext(html.fromstring(
                "<b>text0<i>text1</i><ul><li>item1</li>"
                "<li>item2</li></ul>text2<b/><b>sib</b>"))))

出力

['text0', 'text1', ['item1', 'item2'], 'text2', 'sib']

注: Python 3.3 より古いバージョンでは、yield from Xに置き換えることができます。for x in X: yield x

隣接する文字列を結合するには:

def joinadj(iterable, join=' '.join):
    adj = []
    for item in iterable:
        if isinstance(item, str):
            adj.append(item) # save for later
        else:
            if adj: # yield items accumulated so far
                yield join(adj)
                del adj[:] # remove yielded items
            yield item # not a string, yield as is

    if adj: # yield the rest
        yield join(adj)

print(list(joinadj(itertext(html.fromstring(
                "<b>text0<i>text1</i><ul><li>item1</li>"
                "<li>item2</li></ul>text2<b/><b>sib</b>")))))

出力

['text0 text1', ['item1', 'item2'], 'text2 sib']

テーブルを許可するには<ul>、ハンドラ内のネストされたリストをitertext()再帰的に呼び出す必要があります。

def ul_handler(el):
    yield list(itertext(el, with_tail=False))
    if el.tail:
        yield el.tail

def itertext(root, handlers=dict(ul=ul_handler), with_tail=True):
    if root.text:
        yield root.text
    for el in root:
        yield from handlers.get(el.tag, itertext)(el)
    if with_tail and root.tail:
        yield root.tail

print(list(joinadj(itertext(html.fromstring(
                    "<b>text0<i>text1</i><ul><li>item1</li>"
                    "<li>item2<ul><li>sub1<li>sub2</li></ul></ul>"
                    "text2<b/><b>sib</b>")))))

出力

['text0 text1', ['item1', 'item2', ['sub1', 'sub2']], 'text2 sib']
于 2012-07-26T21:37:47.413 に答える