#其實從PHP5開始,PHP就為我們提供了一個強大的解析和產生XML相關操作的類,也就是我們今天要講的DOMDocument 類別。不過我估計大部分人在爬取網頁時還是會喜歡用正則去解析網頁內容,學了今天的這個類下回就可以嘗試下使用這個PHP自帶的方式來進行解析分析了。
解析HTML
// 解析 HTML $baidu = file_get_contents('https://www.baidu.com'); $doc = new DOMDocument(); @$doc->loadHTML($baidu); // 百度输出框 $inputSearch = $doc->getElementById('kw'); var_dump($inputSearch); // object(DOMElement)#2 // .... echo $inputSearch->getAttribute('name'), PHP_EOL; // wd // 获取所有图片的链接 $allImageLinks = []; $imgs = $doc->getElementsByTagName('img'); foreach($imgs as $img){ $allImageLinks[] = $img->getAttribute('src'); } print_r($allImageLinks); // Array // ( // [0] => //www.baidu.com/img/baidu_jgylogo3.gif // [1] => //www.baidu.com/img/bd_logo.png // [2] => http://s1.bdstatic.com/r/www/cache/static/global/img/gs_237f015b.gif // ) // 利用 parse_url 分析链接 foreach($allImageLinks as $link){ print_r(parse_url($link)); } // Array // ( // [host] => www.baidu.com // [path] => /img/baidu_jgylogo3.gif // ) // Array // ( // [host] => www.baidu.com // [path] => /img/bd_logo.png // ) // Array // ( // [scheme] => http // [host] => s1.bdstatic.com // [path] => /r/www/cache/static/global/img/gs_237f015b.gif // )
是不是感覺好清晰,好有物件導向的感覺。就像第一次使用 ORM函式庫 來進行資料庫操作的感覺。我們一段一段來看。
$baidu = file_get_contents('https://www.baidu.com'); $doc = new DOMDocument(); @$doc->loadHTML($baidu);
首先是載入文件內容,這個比較好理解,直接使用 loadHTML() 方法載入 HTML 內容。它也提供了其它的幾個方法,分別是:load() 從一個檔案載入XML;loadXML() 從字串載入XML;loadHTMLFile() 從檔案載入HTML。
// 百度输出框 $inputSearch = $doc->getElementById('kw'); var_dump($inputSearch); // object(DOMElement)#2 // .... echo $inputSearch->getAttribute('name'), PHP_EOL; // wd
接下來我們使用和前端 JS 一樣的 DOM 操作API來操作HTML裡面的元素。這個範例中就是取得百度的文字框,直接使用 getElementById() 方法得到id為指定內容的 DOMElement 物件。然後就可以取得它的值、屬性之類的內容了。
【相關推薦:PHP影片教學】
// 获取所有图片的链接 $allImageLinks = []; $imgs = $doc->getElementsByTagName('img'); foreach($imgs as $img){ $allImageLinks[] = $img->getAttribute('src'); } print_r($allImageLinks); // Array // ( // [0] => //www.baidu.com/img/baidu_jgylogo3.gif // [1] => //www.baidu.com/img/bd_logo.png // [2] => http://s1.bdstatic.com/r/www/cache/static/global/img/gs_237f015b.gif // ) // 利用 parse_url 分析链接 foreach($allImageLinks as $link){ print_r(parse_url($link)); } // Array // ( // [host] => www.baidu.com // [path] => /img/baidu_jgylogo3.gif // ) // Array // ( // [host] => www.baidu.com // [path] => /img/bd_logo.png // ) // Array // ( // [scheme] => http // [host] => s1.bdstatic.com // [path] => /r/www/cache/static/global/img/gs_237f015b.gif // )
這一段範例則是取得HTML文件中所有的圖片連結。相較於正規來說,是不是方便很多,而且程式碼本身就是自解釋的,不用考慮正規的匹配失效的問題。配合另外一個PHP中自帶的 parse_url() 方法也能非常方便地對連結進行分析,提取自己想要的內容。
XML的解析和對HTML的解析也是類似的,都使用 DOMDocument 和 DOMElement 提供的這個方法介面就可以很方便的進行解析了。那我們想要產生一個標準格式的XML呢?當然也非常的簡單,不需要再去拼接字串了,使用這個類別一樣的進行物件化的操作。
產生一個XML
// 生成一个XML文档 $xml = new DOMDocument('1.0', 'UTF-8'); $node1 = $xml->createElement('First', 'This is First Node.'); $node1->setAttribute('type', '1'); $node2 = $xml->createElement('Second'); $node2->setAttribute('type', '2'); $node2_child = $xml->createElement('Second-Child', 'This is Second Node Child.'); $node2->appendChild($node2_child); $xml->appendChild($node1); $xml->appendChild($node2); print $xml->saveXML(); /* 930406f08da8ee4a2ff134b688d29d1d 80d0a44fb52501b45210d19567744c44This is First Node.02ef1716f0c25a19a37dfb5f194429ec 51072466d8dba7b78b124cb14fb072b50e06ead6eda9a04ee89f206a4868bdd8This is Second Node Child.a031e6b623a487c16282de8e8361d440e6d0d204f222d3c70ad56d061fe9b19f */
其實只要有一點點的前端 JS 的基礎都不難看出這段程式碼的意思。使用 createElement() 方法建立 DOMElement 對象,然後就可以為它添加屬性和內容。使用 appendChild() 方法就可以為目前的 DOMElement 或 DOMDocument 新增下級節點。最後使用 saveXML() 就能夠產生標準的XML格式內容了。
總結
透過上面兩個簡單的小例子,相信大家已經對這個 DOMDocument 操作XML類別檔案解析的方式非常感興趣了。不過相對於正則解析的方式它們的性能有多大的差異並沒有找到相關的測試,不過一般正常的情況下網站的HMTL文檔都不會太大,畢竟各個網站也會考慮自身的加載速度,如果文檔非常大的話使用者體驗也會很差,所以這套介面用來進行日常爬蟲的分析處理工作基本上是沒有任何問題的。
測試程式碼:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202002/source/PHP%E4%B8%AD%E4%BD%BF%E7%94%A8DOMDocument%E6%9D%A5%E5%A4%84%E7%90%86HTML%E3%80%81XML%E6%96%87%E6%A1%A3.php
參考文件:
https://www.php.net/manual/zh/class.domdocument.php