PHP版的jQuery

edithfang發表於2014-11-19
但問題在在於,只有前端程式設計師可以利用jQuery的強力,他們可以用它分析HTML,根據CCS類,HTML屬性,CSS規則等各種選擇器來查詢、獲取、操作HTML裡的任何一個元素。而作為後端(服務端)程式設計師來說,他們同樣需要分析HTML內容,從HTML中提取符合要求的HTML片段、獲取某個符合條件的屬性值等。

遇到這種情況,後端程式設計師通常的做法就是用正規表示式、或用XML解析器。這些做法非常的笨拙,不方便,效率低下。所以,對於在伺服器端解析HTML,每個後端程式設計師都極力避免。

我是一個PHP程式設計師,最近就遇到了這樣的一個任務,需要在伺服器端解析HTML,將裡面的標題名稱和連結提取出來。最初我想開發一個小程式逐行分析HTML,捕捉關鍵字,或用正規表示式。但簡單分析了一下,這樣做實在不可取。因為我也是個Web程式設計師,經常使用jQuery解析HTML頁面上的內容。如果這個任務放到瀏覽器端執行,太簡單了,只需要一句程式碼:

jQuery('.title').each(...);,如何能在伺服器端也能像jQuery那樣進行HTML DOM查詢呢?

實際上,在伺服器端有不少具有jQuery功能的PHP程式庫。在網上稍微做了點功夫,就搜到了10幾個聲稱都能解析HTML的PHP工具。但經過試驗,大部分都多少有這樣或那樣的缺陷,而且都有一個通病,就是中文亂碼問題。最終,我選用了一個叫做phpQuery的工具包。

實際上,使用phpQuery這個PHP程式庫也是很不情願的,因為這個程式已經很多年沒人維護更新了。但比起其它幾個類似功能程式庫,例如Zend_Dom、QueryPath、SimpleHtmlDom,它算是好的。

phpQuery的介面很豐富,但很簡單。一個基本的用法是這樣的:

$list = phpQuery::newDocumentFileHTML('http://www.webhek.com')->find('h2.titl
e a'); 
foreach($list as $e) { 
     $title = $e->nodeValue; 
     $url = $e->getAttribute('href'); 
}


上面的find()方法返回的物件是PHP官方擴充套件庫中的DOM物件,也就是說,phpQuery是一個基於PHP原生的DOM物件的HTML/XML解析器,這樣做的好處是,效率很高。相反,像SimpleHtmlDom這樣也是分析HTML/XML的程式庫,但沒有基於PHP原生DOM物件,當分析大資料量時,很容易產生效能問題,所以不推薦使用。

之前說了,所有的這樣類似jQuery的能分析HTML DOM的PHP程式庫都一個相同的通病:遇到中文會有亂碼。我在使用phpQuery的過程中也遇到了這個問題。

首先PHP中的中文字身就是個問題,而PHP的DOM物件處理中文的方式也是有爭議的。官方文件是說,這個DOM擴充套件包使用的是UTF-8編碼,當遇到 ISO-8859-
1 編碼的文字時,使用 utf8_encode() 和 utf8_decode() 編碼和解碼,遇到其它編碼時,使用Iconv函式進行轉碼。但現實情況比這要複雜的多。網上有很多意見認為在遇到DOM亂碼時,在HTML程式碼裡的<title>標記前加入<meta charset="utf-8">就行了。但這種方法有時候也不靈。

我在解決phpQuery的中文亂碼問題也是反覆嘗試才最後搞定的,沒有任何理論依據。就像是有個程式設計師的笑話:這段程式碼不好用,我不知道為什麼。這段程式碼好用,我也不知道為什麼。:(

首先我是在桌上型電腦上開發測試的,是Window7,這種環境下會出現兩種情況,一種情況是HTML的字符集是GBK/gb2312,一種情況是字符集是UTF-8。奇怪的是,兩個同樣是gb2312字符集的不同頁面,用phpQuery解析後,一個會有亂碼,一個沒有亂碼。同樣,兩個同樣是UTF-8字符集的不同頁面,也會出現這種情況。所有,對我來說,沒有規律可言。我只能說,這兩種方法能解決phpQuery使用過程中出現的亂碼,但何時使用哪種?我不知道,你只能兩個都試一下,會有一個好用。

所以,有亂碼出現時,首先使用第一種方案:

//仍然使用上面的程式碼例子: 
$list = phpQuery::newDocumentFileHTML('http://www.webhek.com')->find('h2.titl
e a'); 
foreach($list as $e) {
      $title = $e->nodeValue;  
    //進行GBK轉碼  
      $title = iconv("UTF-8","GBK", $title); 
}


如果不行,使用第二種方案:

//仍然使用上面的程式碼例子: 
//指定GBK字符集引數 
$list = phpQuery::newDocumentFileHTML('http://www.webhek.com','GBK')->find(
'h2.title a'); 
foreach($list as $e) { 
    $title = $e->nodeValue; 
}


第一種方案中要使用iconv函式進行轉碼,第二種方案中不需要iconv轉碼,但需要在newDocumentFileHTML方法上提供“GBK字符集”。

還有一點很重要,在使用iconv函式轉碼是,一定要使用GBK,而不是使用gb2312,如果使用gb2312,iconv函式會很容易發生非法字元的報錯,使得轉碼失敗。

我以為有了這兩種方案護航後,亂碼問題再不會出現。可是,你要知道,做程式設計師很容易的心臟病的。當我把這些程式碼部署到linux伺服器上時,亂碼依舊。抓狂。

沒辦法,程式設計師的生活就是這樣。經過除錯,發現,在linux伺服器上,採用第二種方案的部分網頁仍然正常,但使用第一種方案時,需要去掉iconv函式轉碼。

下輩子一定不要做程式設計師。
評論(1)

相關文章