2015-05-01 32 views
1

我使用PHP DomDocument + XPath來刮取各種網頁。我發現在某些情況下,DomDocument甚至無法加載HTML,只是返回一個空的結果。例如,頁面包含兩個主體標籤或具有錯誤的DOCTYPE聲明。我試圖用PHP Tidy預處理格式錯誤的HTML,它確實有幫助,但PHP Tidy非常慢!使用PHP DomDocument刮取格式不正確的HTML

我不希望使用任何第三方庫,例如Simple Html Dom Parser

請告知如何處理使用PHP的DomDocument畸形的HTML。我應該在發送到DomDocument之前編寫自定義正則表達式來修復損壞的HTML嗎?也許我錯過了PHP DomDocument的一些設置?

UPD

$ch = curl_init(); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
curl_setopt($ch, CURLOPT_URL, 'http://example.com'); 
$result = curl_exec($ch); 
curl_close($ch); 

$dom = new DomDocument; 
libxml_use_internal_errors(true); 
$dom->loadHTML($result); 
libxml_clear_errors(); 
var_dump($dom); 

$xpath = new DomXPath($dom); 
$nodes = $xpath->query(".//*[@id='content']/ul/li/div[2]/h3/a"); 

var_dump($nodes); // Nothing 

的var_dump($ DOM)的結果;

object(DOMDocument)#25 (34) { 
    ["doctype"]=> 
    string(22) "(object value omitted)" 
    ["implementation"]=> 
    string(22) "(object value omitted)" 
    ["documentElement"]=> 
    NULL 
    ["actualEncoding"]=> 
    string(5) "UTF-8" 
    ["encoding"]=> 
    string(5) "UTF-8" 
    ["xmlEncoding"]=> 
    string(5) "UTF-8" 
    ["standalone"]=> 
    bool(true) 
    ["xmlStandalone"]=> 
    bool(true) 
    ["version"]=> 
    NULL 
    ["xmlVersion"]=> 
    NULL 
    ["strictErrorChecking"]=> 
    bool(true) 
    ["documentURI"]=> 
    NULL 
    ["config"]=> 
    NULL 
    ["formatOutput"]=> 
    bool(false) 
    ["validateOnParse"]=> 
    bool(false) 
    ["resolveExternals"]=> 
    bool(false) 
    ["preserveWhiteSpace"]=> 
    bool(true) 
    ["recover"]=> 
    bool(false) 
    ["substituteEntities"]=> 
    bool(false) 
    ["nodeName"]=> 
    string(9) "#document" 
    ["nodeValue"]=> 
    NULL 
    ["nodeType"]=> 
    int(13) 
    ["parentNode"]=> 
    NULL 
    ["childNodes"]=> 
    string(22) "(object value omitted)" 
    ["firstChild"]=> 
    string(22) "(object value omitted)" 
    ["lastChild"]=> 
    string(22) "(object value omitted)" 
    ["previousSibling"]=> 
    NULL 
    ["attributes"]=> 
    NULL 
    ["ownerDocument"]=> 
    NULL 
    ["namespaceURI"]=> 
    NULL 
    ["prefix"]=> 
    string(0) "" 
    ["localName"]=> 
    NULL 
    ["baseURI"]=> 
    NULL 
    ["textContent"]=> 
    string(0) "" 
} 

UPD2。對於DomDocument,重複<body>即可。有在html領先的空格,加入trim()$dom->loadHTML(trim($result));

+1

我們可以看到造成它失敗的最短可能的例子嗎?兩個身體標籤是一個相當嚴重的腐敗。這是你唯一需要處理的情況嗎? – halfer

+1

兩個body標籤是可怕的HTML,但有效的XML和DOMDocument可以處理標籤湯。所以,對於DD來說,HTML的一個例子可能太多了,這很有趣。另請參閱我對其他想法的回答。 –

+0

到目前爲止,我有兩種情況 - 重複body標籤錯誤的DOCTYPE,如<!DOCTYPE html xmlns =「http://www.w3.org/1999/xhtml」xmlns:fb =「http://ogp.me/ns/fb#「xmlns:og =」http://ogp.me/ns#「>,但會更多 – ymakux

回答

1

DOMDocumentloadHTML()方法解決科佩斯相當好與畸形的HTML但它會產生大量的錯誤。您將要向上冒泡到您的默認錯誤處理程序是這樣抑制這些錯誤:

<?php 
// some process of fetching the HTML page 
$doc = new DOMDocument(); 
libxml_use_internal_errors(true); 
$doc->loadHTML($scrappedPage); 

它可能使用curl搶文件被廢棄,如果你不這樣做是值得的,它傳遞給DOMDocument之前確保你在處理非常糟糕的HTML時不會遇到超時問題。這也將使您能夠在本地捕獲文件並檢查遇到的錯誤。這也意味着你會有一個格式不正確的HTML例子來顯示你的下一個問題。

由於PHP 5.4.0和Libxml 2.6.0,您還可以使用可選的options參數來提供額外的Libxml參數。有些可能是有用的:

  • LIBXML_HTML_NODEFDTD:防止在沒有找到一個
  • LIBXML_PARSEHUGE添加默認文檔類型:放寬從解析器任何硬編碼限制。這會影響文檔的最大深度或實體遞歸等限制,以及文本節點大小的限制。
  • 瞭解更多:http://php.net/manual/en/libxml.constants.php
0

我應該寫一個自定義的正則表達式發送給的DomDocument前修復損壞的HTML?

在您還沒有使用Tidy之前,您已經理解了它爲什麼不適合您,並且您已經清楚瞭解正則表達式在特定情況下(以安全且穩定的方式)的可能性。

也許我錯過了一些PHP DomDocument的設置?

也許錯誤處理(見libxml_use_internal_errors())和DOMDocument::$recover字段。

但是肯定的是,您已經錯過了很多現有的Q &我們現場已有的關於該主題的材料。它包含更多的建議,我認爲有10多個問題可以解決單獨提供部分問題的錯誤。