无法从网站抓取内容


unable to scrape content from a website

我正在尝试从网站上抓取一些内容,但下面的代码不起作用(不显示任何输出(。这是代码

$url="some url";
$otherHeaders="";   //here i am using some other headers like content-type,userAgent,etc
some curl to get the webpage
...
..
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
$content=curl_exec($ch);curl_close($ch);
$page=new DOMDocument();
$xpath=new DOMXPath($page); 
$content=getXHTML($content);  //this is a tidy function to convert bad html to xhtml 
$page->loadHTML($content);    // its okay till here when i echo $page->saveHTML the page is displayed
$path1="//body/table[4]/tbody/tr[3]/td[4]";
$path2="//body/table[4]/tbody/tr[1]/td[4]";
$item1=$xpath->query($path1);
$item2=$xpath->query($path2);
echo $item1->length;      //this shows zero 
echo $item2->length;      //this shows zero
foreach($item1 as $t)
echo $t->nodeValue;    //doesnt show anything
foreach($item2 as $p)
echo $p->nodeValue;    //doesnt show anything

我确定上面的xpath代码有问题。 xpaths是正确的。我已经用FirePath (a firefox addon)检查了上述xpaths.我知道我在这里错过了一些非常愚蠢的东西,但我无法辨认。请帮忙。我已经检查了类似的代码以从Wikipedia中抓取链接(肯定xpaths不同(,并且效果很好。所以我不明白为什么上面的代码不适用于其他URLs.我正在用Tidy清理HTML内容,所以我没有xpath没有HTML的问题,对吗?我已经检查了$item1=$xpath->query($path1)nodelist的长度,这是0这意味着$xpath->query出了问题,因为我已经检查了xpaths是正确的FirePath我已经按照指出修改了我的代码,并使用了loadXML而不是loadHTML。但这给了我错误Entity 'nbsp' not defined in Entity所以我使用 libxml 选项LIBXML_NOENT来替换实体,但错误仍然存在。

是的,你缺少一些非常基本的东西:它是XHTML,所以你必须注册(并使用!(正确的命名空间,然后才能期望得到结果。

$xpath->registerNamespace('x', 'http://www.w3.org/1999/xhtml');
$path1="//x:body/x:table[4]/x:tbody/x:tr[3]/x:td[4]";
$path2="//x:body/x:table[4]/x:tbody/x:tr[1]/x:td[4]";
$item1=$xpath->query($path1);
$item2=$xpath->query($path2);

似乎这个问题与 XPath 和命名空间有关。PHP手册揭示了一个有趣的用户评论

如果已注册命名空间, 将您的 XHTML 等加载到您的 XPath 的 DOMDocument 对象和 仍然无法让它工作, 检查以确保您没有使用 DOMDocument's loadHTML(( 或 loadHTMLFile(( 函数。对于 XHTML 始终使用 XML 版本, 否则你的XPath永远不会,永远不会 工作。

您的代码使用loadHTML()

$content=getXHTML($content);  //this is a tidy function to convert bad html to xhtml 
$page->loadHTML($content);    // its okay till here when i echo $page->saveHTML the page is displayed

HTML 不是命名空间感知的,因此loadHTML()可能不会在文档对象的元素上设置命名空间,即使原始文档(或 Tidy 输出的 XHTML(具有命名空间。

因为您使用 Tidy 将文档转换为 XHTML,所以我想您可以安全地使用 loadXML()而不会遇到解析错误。请注意,它要求输入是格式正确的 XML。此外,它可能不知道 HTML 预定义的实体(如  (,如果是这种情况,它无法将实体替换为正确的字符值。如果出现此类问题,请尝试为 loadXML() 设置不同的选项。

我听说FireFox会添加一个tbody元素,如果不存在的话

除了 @Tomalak 的建议之外或独立于 的建议,请尝试删除/tbody位置步骤的 XPath 表达式。

此外,使用另一个工具作为 XPath

可视化工具来构造正确的 XPath 表达式,并立即查看它们正在选择的内容。

这个问题提醒我,很多时候问题的解决方案在于简单而不是复杂。 我正在尝试namespaceserror corrections等,但解决方案只是要求仔细检查代码。我的代码问题是loadHTML()xpath initialization的顺序。最初订单是

$xpath=new DOMXPath($page);
$page->loadHTML($content);

通过这样做,我实际上是在一个空文档上初始化xapth。 现在通过首先使用 html 加载dom然后初始化xpath来反转顺序,我能够获得所需的结果。还建议通过从xpath中删除tbody元素,firefox自动插入它。所以正确的xpath应该是

$path1="//body/table[4]/tr[3]/td[4]";
$path2="//body/table[4]/tr[1]/td[4]";

感谢大家的建议和承担这一点。

(尝试将以下内容与其他答案结合使用或分开,因为它们是其他可能的警告。

如果您的 XPath 不起作用,请尝试仅应用其中的一部分,以确保您确实遵循了正确的路径。所以做这样的事情:

$path1="//body";
$item1 = $xpath->query($path1);
foreach ($item1 as $t) {
    // to see the full XML of the returned node, as the nodeValue may be empty
    echo $t->ownerDocument->saveXML($t); 
}

然后继续将你的 XPath 增加到你想要的位置。

此外,如果您发现节点的 nodeValue 和 textContent 为空,则应确保使用正确的编码加载到 DOMDocument 中(例如,如果 cURL 响应返回 UTF-8,则需要在构造 DOMDOcument 时传递"UTF-8"作为第二个参数(。