2010-08-21 150 views
1

解析HTML/JS代碼以使用PHP獲取信息。如何使用PHP解析HTML頁面?

www.asos.com/Asos/Little-Asos-Union-Jack-T-Shirt/Prod/pgeproduct.aspx?iid=1273626

看看這個頁面,這是一個兒童服裝店。這是他們的項目之一,我想指出尺寸部分。我們在這裏需要做的是獲得這個項目的所有尺寸,並檢查尺寸是否可用。現在這個項目的所有尺寸是:

3-4 years 
4-5 years 
5-6 years 
7-8 years 

你怎麼能說如果大小是否可用?

現在看看這個頁面第一,並再次檢查尺寸:

www.asos.com/Ralph-Lauren/Ralph-Lauren-Long-Sleeve-Big-Horse-Stripe-Rugby-Top/ ?PROD/pgeproduct.aspx IID = 1111751

此產品具有以下尺寸:

12 months 
18 months - Not Available 
24 months 

正如你可以參見第18個月尺寸是不可用的,它是由「不可用」文本顯示旁邊尺寸。

我們需要做的是去一個項目的頁面,獲取尺寸,並檢查每個尺寸的可用性。我怎樣才能在PHP中做到這一點?

編輯:

添加一個工作代碼,並解決新的問題。

工作的代碼,但它需要更多的工作:

<?php 

function getProductVariations($url) { 

    //Use CURL to get the raw HTML for the page 
    $ch = curl_init(); 
    curl_setopt_array($ch, 
    array(
     CURLOPT_RETURNTRANSFER=>true, 
     CURLOPT_HEADER => false, 
     CURLOPT_URL => $url 
    ) 
); 
    $raw_html = curl_exec($ch); 

    //If we get an invalid response back from the server fail 
    if ($raw_html===false) { 
    throw new Exception(curl_error($ch)); 
    } 

    curl_close($ch); 

    //Find the variation JS declarations and extract them 
    $raw_variations = preg_match_all("/arrSzeCol_ctl00_ContentMainPage_ctlSeparateProduct\[[0-9]+\].*Array\((.*)\);/",$raw_html,$raw_matches); 

    //We are done with the Raw HTML now 
    unset($raw_html); 

    //Check that we got some results back 
    if (is_array($raw_matches) && isset($raw_matches[1]) && sizeof($raw_matches[1])==$raw_variations && $raw_variations>0) { 

    //This is where the matches will go 
    $matches = array(); 

    //Go through the results of the bracketed expression and convert them to a PHP assoc array 
    foreach($raw_matches[1] as $match) { 

     //As they are declared in javascript we can use json_decode to process them nicely, they just need wrapping 
     $proc=json_decode("[$match]"); 

     //Label the fields as best we can 
     $proc2=array(
     "variation_id"=>$proc[0], 
     "size_desc"=>$proc[1], 
     "colour_desc"=>$proc[2], 
     "available"=>(trim(strtolower($proc[3]))=="true"), 
     "unknown_col1"=>$proc[4], 
     "price"=>$proc[5], 
     "unknown_col2"=>$proc[6],  /*Always seems to be zero*/ 
     "currency"=>$proc[7], 
     "unknown_col3"=>$proc[8], 
     "unknown_col4"=>$proc[9],  /*Negative price*/ 
     "unknown_col5"=>$proc[10],  /*Always seems to be zero*/ 
     "unknown_col6"=>$proc[11]  /*Always seems to be zero*/ 
    ); 

     //Push the processed variation onto the results array 
     $matches[$proc[0]]=$proc2; 

     //We are done with our proc2 array now (proc will be unset by the foreach loop) 
     unset($proc2); 
    } 

    //Return the matches we have found 
    return $matches; 

    } else { 
    throw new Exception("Unable to find any product variations"); 

    } 
} 


//EXAMPLE USAGE 
try { 
    $variations = getProductVariations("http://www.asos.com/Asos/Prod/pgeproduct.aspx?iid=803846"); 

    //Do something more useful here 
    print_r($variations); 


} catch(Exception $e) { 
    echo "Error: " . $e->getMessage(); 
} 

?> 

上面的代碼工作,但是當產品需要您先選擇一種顏色,顯示尺寸之前,有一個問題。

贊一個:

http://www.asos.com/Little-Joules/Little-Joules-Stewart-Venus-Fly-Trap-T-Shirt/Prod/pgeproduct.aspx?iid=1171006

不知道如何着手呢?

+0

我剛剛發現選擇大小的選項由AJAX填充。如您所見,這是尺寸選擇DIV。填充此DIV的信息顯然來自AJAX與後端腳本的交互。單詞「不可用」不在HTML中,但當您打開SELECT窗體控件時,它們在屏幕上清晰呈現。因此,他們以其他方式進入DOM。 fopen和file_get_contents在這裏還能工作嗎? – GoDesigner 2010-08-21 13:58:18

回答

3

SOLUTION:

function curl($url){ 
     $ch = curl_init(); 
     curl_setopt($ch, CURLOPT_URL,$url); 
     curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); 
     return curl_exec($ch); 
     curl_close ($ch); 
    } 

$html = curl('http://www.asos.com/pgeproduct.aspx?iid=1111751'); 

preg_match_all('/arrSzeCol_ctl00_ContentMainPage_ctlSeparateProduct\[(.*?)\] \= new Array\((.*?),\"(.*?)\",\"(.*?)\",\"(.*?)\"/is',$html,$bingo); 

echo print_r($bingo); 

鏈接:http://debconf11.com/stackoverflow.php

你是你自己現在:)

EDIT2:

好了,我們已經接近解決方案...

<script type="text/javascript">var arrSzeCol_ctl00_ContentMainPage_ctlSeparateProduct = new Array; 
arrSzeCol_ctl00_ContentMainPage_ctlSeparateProduct[0] = new Array(1164,"12 months","SailingOrange","True","","59.00","0.00","£","","-59.00","0.00","0"); 
arrSzeCol_ctl00_ContentMainPage_ctlSeparateProduct[1] = new Array(1165,"18 months","SailingOrange","False","","59.00","0.00","£","","-59.00","0.00","0"); 
arrSzeCol_ctl00_ContentMainPage_ctlSeparateProduct[2] = new Array(1167,"24 months","SailingOrange","True","","59.00","0.00","£","","-59.00","0.00","0"); 
</script> 

它不是通過ajax加載的,而是數組在javascript變量中。你可以用PHP解析這個,你可以清楚地看到18個月是一個假,這意味着它不可用。

編輯:

該尺寸通過JavaScript加載的,所以你不能解析它們,因爲它們不存在。 我只能這樣提取...

<select name="drpdwnSize" id="ctl00_ContentMainPage_ctlSeparateProduct_drpdwnSize" onchange="drpdwnSizeChange(this, 'ctl00_ContentMainPage_ctlSeparateProduct', arrSzeCol_ctl00_ContentMainPage_ctlSeparateProduct);"> 
<option value="-1">Select Size</option> 
</select> 

您可以嗅出JS以檢查是否可以加載基於產品ID的大小。


首先,你需要:http://simplehtmldom.sourceforge.net/ 忘記的file_get_contents()是〜5比捲曲慢。

你然後解析這段代碼(HTML ID爲ctl00_ContentMainPage_ctlSeparateProduct_drpdwnSize)

 <select id="ctl00_ContentMainPage_ctlSeparateProduct_drpdwnSize" name="ctl00$ContentMainPage$ctlSeparateProduct$drpdwnSize" onchange="drpdwnSizeChange(this, 'ctl00_ContentMainPage_ctlSeparateProduct', arrSzeCol_ctl00_ContentMainPage_ctlSeparateProduct);"> 

     <option value="-1">Select Size</option><option value="1164">12 months</option><option value="1165">18 months - Not Available</option><option value="1167">24 months</option></select> 

然後可以使用的preg_match(),爆炸(),str_replace()函數和其他過濾出你想要的值。我可以寫,但我現在沒有時間:)

+0

建議的第三方替代品,實際使用DOM而不是字符串分析:[phpQuery](http://code.google.com/p/phpquery/),[Zend_Dom](http://framework.zend.com/manual/ en/zend.dom.html),[QueryPath](http://querypath.org/)和[FluentDom](http://www.fluentdom.org)。 – Gordon 2010-08-21 13:54:56

+0

我發現以及尺寸選擇由JavaScript填充。現在我更加迷失了該做什麼,什麼是嗅探JS? – GoDesigner 2010-08-21 14:00:17

+0

要檢查從哪個腳本(服務器端)加載的大小,我試圖找到,但這只是一團糟。它有大量的JS,我不確定它是否需要。請稍等...... – 2010-08-21 14:09:14

1

獲取URL內容的最簡單方法是依靠fopen包裝器,並僅使用file_get_contents和URL。您可以使用整潔擴展來解析HTML並提取內容。 http://php.net/tidy

1

你可以下載使用fopen()file_get_contents()的文件,如拉烏爾公爵說,但如果你有使用JavaScript DOM模型的經驗,DOM extension可能會更容易一點比整潔使用。

我知道一個事實,即默認情況下在PHP中啓用了DOM擴展,但是我有點不確定是否Tidy是(手冊頁只是說它是「bundeled」,所以我懷疑它可能沒有啓用) 。