6

Web サイトから一部のコンテンツを破棄しようとしていますが、以下のコードが機能していません (出力が表示されません)。ここにコードがあります

$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正しいです。以上xpathsで確認しましたFirePath (a firefox addon)。ここで非常にばかげた何かが欠けていることは知っていますが、わかりません。助けてください。リンクをスクレイピングするための同様のコードをチェックしましたWikipedia(間違いなくxpaths異なります)が、うまく機能します。したがって、上記のコードが他のコードでは機能しない理由がわかりませんURLs。私はHTMLコンテンツをクリーニングしてTidyいるので、xpathがHTMLを正しく取得していないという問題はありませんか? nodelist後 の長さを確認しました$item1=$xpath->query($path1)。これは、確認したように正しいため、0何か問題が発生していることを意味します$xpath->queryxpathsFirePathloadXMLの代わりに 指摘され使用されているように、コードを少し変更しましたloadHTML。しかし、これによりエラーが発生するため、エンティティを置き換えるオプションをEntity 'nbsp' not defined in Entity使用しましたが、それでもエラーは残ります。libxmlLIBXML_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)に名前空間が含まれていても、ドキュメントオブジェクトの要素に名前空間が設定されない場合があります。

loadXML()Tidyを使用してドキュメントをXHTMLに変換するため、解析エラーが発生することなく安全に使用できると思います。入力が整形式のXMLである必要があることに注意してください。また、HTMLで事前定義されたエンティティを認識していない可能性があり ます。その場合、エンティティを正しい文字値に置き換えることはできません。このような問題が発生した場合は、に別のオプションを設定してみてくださいloadXML()

于 2011-05-31T00:32:50.807 に答える
2

tbodyそのような要素が存在しない場合、FireFox は要素を追加すると聞いたことがあります。

@Tomalak のアドバイスに加えて、またはそれとは別に、場所のステップを削除して XPath 式を試してください。/tbody

また、別のツールをXPath ビジュアライザーとして使用して、正しい XPath 式を作成し、それらが何を選択しているかをすぐに確認します。

于 2011-05-29T16:47:27.687 に答える
1

この質問は、多くの場合、問題の解決策は複雑さではなく単純さにあることを思い出させてくれます。などを試しnamespaceserror correctionsいましたが、解決策はコードの綿密な検査を要求しただけです。私のコードの問題は、loadHTML()との順序でしたxpath initialization。最初の注文は

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

これを行うことで、実際xapthには空のドキュメントで初期化していました。最初に をロードしてから i を初期化することで順序を逆にするdomことhtmlxpath、目的の結果を得ることができました。また、 astbodyから要素を削除すると、自動的に挿入されることも示唆されています。だから正しいはずですxpathfirefoxxpath

$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- DOMDOcument を構築するときの 2 番目のパラメーターとして 8' を指定します)。

于 2011-05-30T12:05:00.537 に答える