2014-10-12 70 views
0

下頁入門價格從亞馬遜使用XPath

http://www.amazon.com/Jessica-Simpson-Womens-Double-Breasted/dp/B00K65ZMCA/ref=sr_1_4_mc/185-0705108-6790969?s=apparel&ie=UTF8&qid=1413083859&sr=1-4 我試圖讓價格與表達

'//span[@id="priceblock_ourprice"]' 

但結果卻是一個空的變量。

有趣的是,在其他亞馬遜的頁面,像這樣的 :http://www.amazon.com/SanDisk-Cruzer-Frustration-Free-Packaging--SDCZ36-032G-AFFP/dp/B007JR532M/ref=sr_1_1?s=pc&ie=UTF8&qid=1413084653&sr=1-1&keywords=usb

我確實有工作

'//b[@class="priceLarge"]' 

的表達,但我不知道爲什麼,因爲在源該網頁我找不到這樣的標籤... 那麼,爲什麼它的工作?以及如何在首頁上獲得價格? 謝謝!

+0

可能是因爲你的瀏覽器中的網頁是一個不同的佈局,則一個在你的PHP – pguardiario 2014-10-12 03:54:53

+0

第一個路徑表達式是正確的,並會產生價格 - 也就是說,如果它正確地應用於數據。 PLease顯示PHP代碼(對於這兩種表達式)。 – 2014-10-12 09:28:08

回答

2

使用PHP進行抓取時,您不能只將您在瀏覽器源代碼中看到的內容視爲理所當然。

相反,你首先需要取得與PHP的內容,然後看看源有:

$url = 'http://www.amazon.com/ ... '; 
$buffer = file_get_contents($url); 

變量$buffer則包含了你會被刮的HTML。

完成,以你的例子鏈接將顯示,第一和第二地址都具有含可能.priceLarge元素,你在找什麼:

<span class="priceLarge">$168.00</span> 
<b class="priceLarge">$14.99</b> 

找出其中的數據是你」之後重新尋找,你可以創建DOM文檔

$doc   = new DOMDocument(); 
$doc->recover = true; 
$saved  = libxml_use_internal_errors(true); 
$doc->loadHTML($buffer); 

您可能也有興趣解析錯誤:

/** @var array|LibXMLError[] $errors */ 
$errors = libxml_get_errors(); 
foreach ($errors as $error) { 
    printf(
     "%s: (%d) [%' 3d] #%05d:%' -4d %s\n", get_class($error), $error->level, $error->code, $error->line, 
     $error->column, rtrim($error->message) 
    ); 
} 
libxml_use_internal_errors($saved); 

因爲這是一種方式,DOMDocument告訴你哪裏出現問題。例如重複的ID值。

加載緩存爲DOM文檔後,您可以創建DOMXPath

$xp = new DOMXPath($doc); 

你會用它來從文檔中獲取的實際值。

例如這兩個例子地址HTML hasshown你正在尋找的信息是包含.listprice.priceLarge#priceBlock

$priceBlock = $doc->getElementById('priceBlock'); 
printf(
    "List Price: %s\nPrice: %s\n" 
    , $xp->evaluate('string(.//*[@class="listprice"])', $priceBlock) 
    , $xp->evaluate('string(.//*[@class="priceLarge"])', $priceBlock) 
); 

這將導致下面的輸出:

List Price: $48.99 
Price: $14.99 

如果你缺少一些東西,在示例中獲得一個父節段元素作爲$priceBlock,不僅可以使用Xpath的相對路徑,還可以幫助調試cas Ë你錯過了一些更詳細的信息:

echo $doc->saveHTML($priceBlock); 

此輸出整個<div>包含例如所有定價信息。

如果你設置自己的一些輔助類,你還可以在使用這個獲得從文檔其他有用的信息,刮它,如顯示的價格塊內的所有標籤/職業組合:

// you can find StringCollector at the end of the answer 
$tagsWithClass = new StringCollector(); 
foreach ($xp->evaluate('.//*/@class', $priceBlock) as $class) { 
    $tagsWithClass->add(sprintf("%s.%s", $class->parentNode->tagName, $class->value)); 
} 
echo $tagsWithClass; 

這則輸出收集字符串及其數量的列表,它是這裏的標記名與他們的階級屬性值:

table.product (1) 
td.priceBlockLabel (3) 
span.listprice (1) 
td.priceBlockLabelPrice (1) 
b.priceLarge (1) 
tr.youSavePriceRow (1) 
td.price (1) 

正如你所看到的,這是第一個例子URL,因爲.pricelarge是一個<b>元素。

這是一個相對簡單的幫手,你可以做更多的事情,比如以樹的形式顯示整個HTML結構。

DomTree::dump($priceBlock); 

它會給你下面的輸出,允許的不僅僅是DOMDocument::saveHTML($node)更好的消費:

`<div id="priceBlock" class="buying"> 
    +"\n\n " 
    `<table class="product"> 
    +<tr> 
    | +<td class="priceBlockLabel"> 
    | | `"List Price:" 
    | +"\n " 
    | +<td> 
    | | `<span id="listPriceValue" class="listprice"> 
    | | `"$48.99" 
    | `"\n " 
    +<tr id="actualPriceRow"> 
    | +<td id="actualPriceLabel" class="priceBlockLabelPrice"> 
    | | `"Price:" 
    | +"\n " 
    | +<td id="actualPriceContent"> 
    | | +<span id="actualPriceValue"> 
    | | | `<b class="priceLarge"> 
    | | | `"$14.99" 
    | | +"\n " 
    | | `<span id="actualPriceExtraMessaging"> 
    | | +"\n  \n\n\n " 
    | | +<span> 
    | | | `"\n  \n " 
    | | +"\n \n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n \n\n\n\n\n& " 
    | | +<b> 
    | | | `"FREE Shipping" 
    | | +" on orders over $35.\n\n\n\n" 
    | | +<a href="/gp/help/customer/display.html/ref=mk_sss_dp_1/191-4381493-1931545?ie=UTF8&no..."> 
    | | | `"Details" 
    | | `"\n\n\n\n\n\n\n\n\n \n\n \n \n\n\n\n\n\n  \n" 
    | `"\n" 
    +<tr id="dealPriceRow"> 
    | +<td id="dealPriceLabel" class="priceBlockLabel"> 
    | | `"Deal Price: " 
    | +"\n " 
    | +<td id="dealPriceContent"> 
    | | +"\n " 
    | | +<span id="dealPriceValue"> 
    | | +"\n " 
    | | +<span id="dealPriceExtraMessaging"> 
    | | `"\n " 
    | `"\n" 
    +<script> 
    | `[XML_CDATA_SECTION_NODE (4)] 
    +<tr id="youSaveRow" class="youSavePriceRow"> 
    | +<td id="youSaveLabel" class="priceBlockLabel"> 
    | | `"You Save:" 
    | +"\n " 
    | +<td id="youSaveContent" class="price"> 
    | | +<span id="youSaveValue"> 
    | | | `"$34.00\n  (69%)" 
    | | `"\n " 
    | `"\n " 
    `<tr> 
     +<td> 
     `<td> 
     `<span> 
      `"o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o..." 

你可以找到它在an answer to Debug a DOMDocument Object in PHPanother one引用。 code is available on github as a gist


StringCollector輔助類

/** 
* Class StringCollector 
* 
* Collect strings and count them 
*/ 
class StringCollector implements IteratorAggregate 
{ 
    private $array; 

    public function add($string) 
    { 
     $entry = & $this->array[$string]; 
     $entry++; 
    } 

    public function getIterator() 
    { 
     return new ArrayIterator($this->array); 
    } 

    public function __toString() 
    { 
     $buffer = ''; 
     foreach ($this as $string => $count) { 
      $buffer .= sprintf("%s (%d)\n", $string, $count); 
     } 
     return $buffer; 
    } 
} 
+0

夢幻般的詳細答案,DomTree是一個非常有用的幫手類! – 2014-10-12 10:26:42