具有相同层次结构的片段示例:
(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>
因此,具有相似结构的片段对应于一个分层树(相同的标签名称,相同的层次结构)。
如何使用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>
答案 0 :(得分:4)
你使事情变得复杂一点,当事情被证明不是False
时,你只需要在最后返回True
。
当两个元素的标记匹配,它们的长度匹配,并且每个配对的子元素相同时,它们是相等的。
Python使用all()
function测试序列中的所有元素是否True
非常简单,并且使用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
答案 1 :(得分:2)
您现有代码失败的原因是,如果有多个子代,我的设置错误;你将它分配给零,然后永远不会增加它,所以你将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
但是,您现有的代码可以更加简洁。你正在测试三个条件: 1)标记匹配 2)相同数量的孩子 3)所有条件适用于每对孩子
这些都是Python中的单行表达式。所以你可以做到以下几点:
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
,就不会做任何不必要的额外计算。< / p>