Symfony Dom爬网程序缺少节点,行为不一致



使用此代码:

use SymfonyComponentDomCrawlerCrawler;
require_once(__DIR__ . '/../vendor/autoload.php');
$html = <<<'HTML'
<!DOCTYPE html>
<html>
<body>
<p class="message">Hello World!</p>
<p>Hello Crawler!</p>
<p>OUTSIDE
<span>
Child SPAN
</span>
<div>
Child DIV
</div>
<p>
Child PARAGRAPH
</p>
</p>
</body>
</html>
HTML;
$crawler = new Crawler($html);
$crawlerFiltered = $crawler->filter('body > p');
$results = [];
$childResults = [];
for ($i=0; $i<count($crawlerFiltered); $i++) {
$results[] = $crawlerFiltered->eq($i)->html();
$children = $crawlerFiltered->eq($i)->children();
if (count($children)) {
for ($j=0; $j<count($children); $j++) {
$childResults[] = $children->eq($j)->html();
}
}
}
echo 'Parent Nodes:' . PHP_EOL;
var_export($results);
echo PHP_EOL;
echo 'Child Nodes:' . PHP_EOL;
var_export($childResults);

我得到的结果:

Parent Nodes:
array (
0 => 'Hello World!',
1 => 'Hello Crawler!',
2 => 'OUTSIDE
<span>
Child SPAN
</span>
',
3 => '
Child PARAGRAPH
',
)
Child Nodes:
array (
0 => '
Child SPAN
',
)

这代表了以下问题:

  1. 子结果:没有DIV或P(只有内联标记(
  2. 父结果:PHARAGRAPH没有标记,与SPAN不一致
  3. 父结果:应仅包含第一个p,因为第二个p(PHARAGRAPH(不包含有body作为父项,但有p

你知道为什么会这样吗?以及如何解决上述问题?

该组件的文档说明:

注意

DomCrawler将尝试自动修复您的HTML以匹配官方规范。例如,如果将<p>标记嵌套在另一个<p>标记中,则它将被移动为父标记的同级标记。这是意料之中的,也是HTML5规范的一部分

使用内置的DomDocument类可能会有更好的运气。大多数HTML解析器都是为处理"标记汤"而设计的,并会尝试纠正感知到的问题。

最新更新