0

同一の階層構造を持つフラグメントの例:

(1)
<div>
  <span>It's a message</span>
</div>

(2)
<div>
  <span class='bold'>This is a new text</span>
</div>

構造が異なるフラグメントの例:

(1)
<div>
  <span><b>It's a message</b></span>
</div>

(2)
<div>
  <span>This is a new text</span>
</div>

そのため、類似した構造を持つフラグメントは、1 つの階層ツリー (同じタグ名、同じ階層構造) に対応します。

lxmlだけで2つの要素(htmlフラグメント)が同じ構造を持っているかどうかを検出するにはどうすればよいですか?

(例よりも)より困難なケースでは適切に機能しない関数があります。

def _is_equal( el1, el2 ):      
    # input: 2 elements with possible equal structure and tag names
    # e.g. root = lxml.html.fromstring( buf )
    # el1 = root[ 0 ]
    # el2 = root[ 1 ]
    # move from top to bottom, compare elements
    result = False  

    if el1.tag == el2.tag:
        # has no children
        if len( el1 ) == len( el2 ):
            if len( el1 ) == 0:             
                return True
            else:
                # iterate one of them, for example el1
                i = 0
                for child1 in el1:
                    child2 = el2[ i ]
                    is_equal2 = _is_equal( child1, child2 )
                    if not is_equal2:
                        return False
                return True                     
        else:
            return False
    else:
        return False

コードは、class='tovar2' を持つ 2 つの div が同一の構造を持っていることを検出できません。

<body>


    <div class="tovar2">
        <h2 class="new">
            <a href="http://modnyedeti-krsk.ru/magazin/product/333193003">
                Куртка  д/д
            </a>
        </h2>
        <ul class="art">
            <li>
                Артикул: <span>1759</span>
            </li>
        </ul>
        <div>
            <div class="wrap" style="width:180px;"> 
                <div class="new">
                    <img src="shop_files/new-t.png" alt="">
                </div>     
                <a class="highslide" href="http://modnyedeti-krsk.ru/d/459730/d/820.jpg" onclick="return hs.expand(this)"> 
                    <img src="shop_files/fr_5.gif" style="background:url(/d/459730/d/548470803_5.jpg) 50% 50% no-repeat scroll;" alt="Куртка  д/д" height="160" width="180"> 
                </a>     
            </div>
        </div>

        <form action="" onsubmit="return addProductForm(17094601,333193003,3150.00,this,false);">
            <ul class="bott ">
                <li class="price">Цена:<br>
                    <span>
                        <b>
                            3 150
                        </b> руб.
                    </span>
                </li>
                <li class="amount">Кол-во:<br><input class="number" onclick="this.select()" value="1" name="product_amount" type="text">
                </li>
                <li class="buy"><input value="" type="submit">
                </li>
            </ul>
        </form>
    </div>


    <div class="tovar2">
        <h2 class="new">
            <a href="http://modnyedeti-krsk.ru/magazin/product/333124803">Куртка  д/д</a>
        </h2>
        <ul class="art">
            <li>
                Артикул: <span>1759</span>
            </li>
        </ul>
        <div>
            <div class="wrap" style="width:180px;"> 
                <div class="new">
                    <img src="shop_files/new-t.png" alt="">
                </div>     
                <a class="highslide" href="http://modnyedeti-krsk.ru/d/459730/d/820.jpg" onclick="return hs.expand(this)"> 
                    <img src="shop_files/fr_5.gif" style="background:url(/d/459730/d/548470803_5.jpg) 50% 50% no-repeat scroll;" alt="Куртка  д/д" height="160" width="180"> 
                </a>      
            </div>
        </div>      

        <form action="" onsubmit="return addProductForm(17094601,333124803,3150.00,this,false);">
            <ul class="bott ">
                <li class="price">Цена:<br>
                    <span>
                        <b>3 150</b> руб.
                    </span>
                </li>
                <li class="amount">Кол-во:<br><input class="number" onclick="this.select()" value="1" name="product_amount" type="text">
                </li>
                <li class="buy">
                    <input value="" type="submit">
                </li>
            </ul>
        </form>
    </div>

    </body>        
4

2 に答える 2

4

あなたは物事を少し複雑にしています.False物事がそうではないことが証明されたときに最後に戻るだけですTrue.

2 つの要素は、タグが一致し、長さが一致し、ペアになっている各子要素が同じ場合に等しくなります。

Python は、シーケンス内のすべての要素がfunctionTrueで本当に簡単かどうかをテストします。これを使用することで、要素の子を適切にペアリングできます。子ペアが等しくない場合、早期に終了します:all()zip()all()

def _is_equal( el1, el2 ):      
    if el1.tag == el2.tag and len(el1) == len(el2):
        return all(_is_equal(c1, c2) for c1, c2 in zip(el1, el2))

    return False
于 2012-10-28T10:56:19.643 に答える
2

既存のコードが失敗する理由は、複数の子がある場合に i が正しく設定されていないためです。それをゼロに割り当ててからインクリメントしないため、el1 の各要素を、同じ位置にある el2 の要素ではなく、el2の最初の要素と比較します。

既存のコードを修正するには、次のようにします。

def _is_equal( el1, el2 ):      
    # input: 2 elements with possible equal structure and tag names
    # e.g. root = lxml.html.fromstring( buf )
    # el1 = root[ 0 ]
    # el2 = root[ 1 ]
    # move from top to bottom, compare elements
    result = False  

    if el1.tag == el2.tag:
        # has no children
        if len( el1 ) == len( el2 ):
            if len( el1 ) == 0:             
                return True
            else:
                # iterate one of them, for example el1
                for i, child1 in enumerate(el1):
                    child2 = el2[ i ]
                    is_equal2 = _is_equal( child1, child2 )
                    if not is_equal2:
                        return False
                return True                     
        else:
            return False
    else:
        return False

ただし、既存のコードをより簡潔にすることができます。3 つの条件をテストしています: 1) タグが一致する 2) 子の数が同じ 3) すべての条件が子のペアごとに保持される

これらはそれぞれ、Python の 1 行の式です。したがって、次のことができます。

def _is_equal(el1, el2):
    return (el1.tag == el2.tag and
            len(el1) == len(el2) and
            all(_is_equal(c1, c2) for c1, c2 in zip(el1, el2)))

and反復している要素のいずれかが実行されるとすぐに短絡してall戻るFalseため、これにより不要な余分な計算が行われないことに注意してください。

于 2012-10-28T11:02:23.730 に答える