PHP简单的HTML DOM解析器提供错误的数据

时间:2013-08-05 00:10:20

标签: php parsing simple-html-dom

我正在使用PHP Simple HTML DOM使用以下HTML解析网页。请注意每个</span>中的额外<li> - 标记。

<li>
  <span class="name">
    <a href="">Link</a> asdasd
  </span>
  </span>
</li>
<li>
  <span class="name">
    <a href="">Link</a> asdasd2
  </span>
  </span>
</li>

我的疑问是:

$lis = $dom->find('li');
foreach ($lis as $li) {
  $spans = $li->find('span');
  foreach ($spans as $span) {
    echo $span->plaintext."<br>";
  }
}

我的输出是:

Link asdasd 
Link asdasd2
-----------
Link asdasd2 
-----------

正如您所看到的,find('span')发现两个跨度作为第一个<li>的子项,并从下一个<span>中获取它可以找到的值(即使它是下一个的孩子) <li>)。删除尾随</span>可解决问题。

我的问题是

  1. 为什么会这样?

  2. 我如何解决这个特殊情况? 其他一切都运作良好,我无法对我的剧本做出重大改变。如果需要,我可以轻松更改DOM查询。

  3. 我正在考虑计算开始和结束标记,如果有太多标记,则剥离一个</span>。由于它们始终为<span> s,是否有一种智能方法可以使用regexp进行检查?

2 个答案:

答案 0 :(得分:1)

$newTxt = preg_replace('/\<\/span\>[\S]*\<\/span\>/','</span>',$txt);

方法'find(x)'是一个重载函数,可以返回等价的:

$e->getElementById(x);
$e->getElementsById(x);
$e->getElementByTagName(x); and
$e->getElementsByTagName(x);

在您的第一个电话中,它会使用最后一个电话。在第三种可能性的第二个$ li中。这可能是一种优化方法,根据API你要问的问题。我猜你在API中发现了一个错误,因为你在两种情况下都要求使用第三个调用:

$e->getElementByTagName();

答案 1 :(得分:1)

1)通过在某处添加</span>来简单地尝试修复额外的<span>。所以现在你有一个不应该存在的额外跨度。为了记录,DomDocument会做同样的事情,尽管可能以更可预测的方式。

2)简化:

foreach ($dom->find('li > span') as $span) {
  echo $span->plaintext."<br>";
}
//     Link asdasd    <br>     Link asdasd2    <br>

现在你告诉它你只想要一个span的孩子li。更好的是,做一些事情:

foreach ($dom->find('span.name') as $span) {
  echo $span->plaintext."<br>";
}

使用这些属性,这就是他们的好处。