6

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

$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正确的。我已经xpathsFirePath (a firefox addon). 我知道我在这里遗漏了一些非常愚蠢的东西,但我无法弄清楚。请帮忙。我已经检查了类似的代码来抓取链接Wikipedia(肯定xpaths是不同的),它工作得很好。所以我不明白为什么上面的代码不适用于其他代码URLs。我正在清理HTML内容,Tidy所以我没有 xpath 没有获取 HTML 的问题吗?我检查了nodelist后面 $item1=$xpath->query($path1)的长度,0这意味着出现问题,$xpath->query因为xpaths我检查过的都是正确的FirePath 我已经按照指出的那样修改了我的代码,并使用loadXMLloadHTML. 但这给了我错误,Entity 'nbsp' not defined in Entity所以我使用了替换实体的libxml选项LIBXML_NOENT,但错误仍然存​​在。

4

5 回答 5

5

是的,您缺少一些非常基本的东西:它是 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);
于 2011-05-29T15:45:58.940 回答
4

似乎问题与 XPath 和命名空间有关。php手册透露了一个有趣的用户评论

如果您已注册命名空间、将 XHTML 等加载到 XPath 的 DOMDocument 对象中, 但仍然无法使其工作,请检查以确保您没有使用 DOMDocument 的 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().

于 2011-05-31T00:32:50.807 回答
2

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

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

此外,使用另一个工具作为XPath Visualizer来构建正确的 XPath 表达式并立即查看它们选择的内容。

于 2011-05-29T16:47:27.687 回答
1

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

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

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

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

感谢大家的建议和承担。

于 2011-06-10T06:47:29.007 回答
0

(结合其他答案或与其他答案分开尝试以下方法,因为它们是其他可能的警告。)

如果您的 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,则需要传递 'UTF- 8' 作为构造 DOMDOcument 时的第二个参数)。

于 2011-05-30T12:05:00.537 回答