Получение цены от Amazon с помощью 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 = рс & т = UTF8 & QID = 1413084653 & стер = 1-1 & ключевые слова = USB

У меня есть выражение, которое работает

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

Но я даже не знаю, почему, потому что в источнике страницы я не могу найти такой тег … Так почему это работает? и как мне получить цену на первой странице? Благодаря!

Related of "Получение цены от Amazon с помощью Xpath"

При очистке с помощью 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> 

Узнав, где находятся данные, вы можете создать DOMDocument :

 $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 сообщает вам, где возникли проблемы. Например, повторяющиеся значения идентификатора.

После загрузки буфера в DOMDocument вы можете создать DOMXPath :

 $xp = new DOMXPath($doc); 

Вы будете использовать его для получения фактических значений из документа.

Например, эти два примера обращаются к HTML hasshown, что информация, которую вы ищете, представляет собой #priceBlock содержащие как .listprice и .priceLarge :

 $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, но также может помочь с отладкой, если вам не хватает некоторых более подробных сведений :

 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> `"ooooooooooooooooooooo ooooooooooooooooo o..." 

Его можно найти в ответе на « Отладка объекта DOMDocument» на PHP и в другом . Код доступен в github как сущность .


Класс помощника 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; } }