Pull to refresh

eBay API: шаг второй

Reading time8 min
Views11K
Привет, хабравчане.

Публикация навеяна этой статьей — «eBay API: Первые шаги» и теоретически может стать её продолжением. Она пригодится тем, кто пытался начать работать с eBay API, не нашел где спросить, что делать и плюнул на это занятие. Или спросил, не дождался ответа и в итоге все равно плюнул.

На истину ни в какой инстанции не претендую и с радостью приму советы по преодолению багов, которые преодолеть так и не удалось.



Прежде всего, хочется оставить небольшую ремарку: начать работать с eBay API быстро — не получится. Катастрофическое количество недосказанностей и нестыковок в документации, недоработки и баги в самом механизме API, неявности и неоднозначности использования комбинаций условий запросов заставляют тестировать каждый шаг по отдельности. И тестировать неоднократно: то, что вчера прекрасно работало, сегодня будет возвращать ошибку, а завтра продолжит работать как ни в чем не бывало.

Впрочем, дабы не возводить напраслину на уважаемую компанию, давайте забудем про предыдущий абзац и все спишем на то, что я просто туп, глуп и недоразвит. И что у настоящего программиста все получится гораздо быстрее и правильнее.

Поэтому если у вас есть рабочий механизм парсинга страниц Ebay — подумайте еще раз, стоит ли переходить на цивилизованный способ получения данных или продолжить время от времени подстраивать парсер под подстоянно изменяющийся дизайн eBay. Тем более что с точки зрения просто покупателя никаких принципиально новых данных вы не получите, а вот например информацию о текущей скидке или обработку события «лот протух, перевыставляем» — потеряете.

Но если вам по долгу службы необходимо следить хотя бы за парой-тройкой тысяч товаров и периодически сверять цены — API вам бесспорно нужен. Мой небольшой проект отчаянно нуждался в автоматизации актуализации цен и добавления новых товаров, а изменения дизайна eBay в 2014 году стали столь часты, что я решил бросить курить перестать парсить, написать зачатки библиотеки по работе с eBay API и заодно начать на старости лет осваивать программирование.

Так как движок проекта написан на PHP, выбора у меня не было, а посему на нем и продолжим.

Начем с функции findItemsAdvanced, что в переводе означает «Найти много товаров по ключевому слову, с совершенно бесполезным результатом для жителей не-США». Затем рассмотрим (наверное уже в следующей статье) другие функции, которые превратят бесполезные ответы в полезные.

Вы уже получили Application Keys как это сказано здесь. Возьмите AppID из Production Keys — из-за того, что баги в Sandbox и Production разные, мы будем сразу работать с «боевой» версией — и подставьте его в нужное место заголовка. Как вы увидите дальше, заголовки в eBay API могут принимать самые разные формы, поэтому я буду приводить их отдельно в каждом конкретном случае.

<?php

	/* ищет товары по ключевым словам ВО ВСЕХ store	
	// в качестве ключевых слов понимает слова, partnumber или itemID
	// не понимает доставку за пределы США
	*/
function findItemsAdvanced($request)
	{
	    $headers = array(
	      'X-EBAY-SOA-SERVICE-NAME:FindingService',
	      'X-EBAY-SOA-OPERATION-NAME:findItemsAdvanced',                              
	      'X-EBAY-SOA-SERVICE-VERSION:1.12.0',
	      'X-EBAY-SOA-GLOBAL-ID:EBAY-US',
	      'X-EBAY-SOA-SECURITY-APPNAME:Ваш_AppID', // AppID будет жить здесь 
	      "X-EBAY-API-REQUEST-ENCODING: XML",    
	      'Content-Type: text/xml;charset=utf-8',
	    );
	    $endpoint = 'http://svcs.ebay.com/services/search/FindingService/v1?';

Остальные значения заголовков можно просто скопировать, они для одинаковы для всех.

Составим запрос.
Все мои запросы относятся к категории «Запчасти для мотоциклов» и ориентированы на тематчиеский раздел eBay USA — «EBAY-MOTORS». Найдите список подходящих вам разделов здесь, список категорий здесь и не забывайте подставлять их в свои запросы.

	    $xmlRequest  = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
	    $xmlRequest .= "<findItemsAdvancedRequest xmlns='http://www.ebay.com/marketplace/search/v1/services'>";

	    $xmlRequest .= "<categoryId>10063</categoryId>"; // 10063 - запчасти для мотоциклов // 6028 - запчасти к транспорту вообще
	    $xmlRequest .= "<descriptionSearch>false</descriptionSearch>"; // иногда может найти полную ерунду, отключено
	    $xmlRequest .= "<keywords>".$request."</keywords>"; // самое главное: текст вашего запроса
	    $xmlRequest .= "<itemFilter><name>Condition</name><value>New</value></itemFilter>"; // состояние товара: новый, б/у и их варианты
	    $xmlRequest .= "<itemFilter><name>FeedbackScoreMin</name><value>3000</value></itemFilter>"; // отсекаем новичков
	    $xmlRequest .= "<itemFilter><name>ListingType</name><value>FixedPrice</value></itemFilter>";  // отсекаем аукционные торги
	    $xmlRequest .= "<itemFilter><name>AvailableTo</name><value>RU</value></itemFilter>"; 
		// эта фича частенько не работает и пропускает товары, которые продавец на самом деле не отправляет в Россию. Сейчас таких продавцов стало намного больше, поэтому мы отстроимся от них в другом запросе еще раз. Чтобы гарантированно не попасть.

	    $xmlRequest .= "<itemFilter><name>PaymentMethod</name><value>PayPal</value></itemFilter>"; 
		// в некоторых странах существуют платежные системы популярнее Paypal. Для нас они недоступны либо труднодоступны, поэтому лучше сразу отсечь продавцов-смельчаков, которые не принимают Paypal. Пусть eBay разбирается с ними сам.

	    $xmlRequest .= "<itemFilter><name>HideDuplicateItems</name><value>true</value></itemFilter>";
		// нам же не нужны дубликаты в выдаче? Уберем их.
		
	   //$xmlRequest .= "<itemFilter><name>ExcludeSeller</name><value>storename</value></itemFilter>"; // на всякий случай: можно исключить вредных и нехороших продавцов из результатов выдачи. Даже если они прикидываются белыми и пушистыми.

	    $xmlRequest .= "<outputSelector>SellerInfo</outputSelector> // посмотрим что за продавцы попали в наши сети


Здесь хотелось бы подробнее остановиться на параметре descriptionSearch.
Description — это область описания лота в самом низу — под фотографиями, расчетом доставки итд. Теоретически продавец может написать там любую ерунду, которая попадет в наш результат и не будет соответствовать нашему запросу.

Например вы ищете слона, а некий продавец продает кота: в заголовке — кот, на фотографии — кот, но в описании сказано что-то вроде «Это огромный кот, настоящий слон!». Этот товар попадет в нашу выдачу, хотя на самом деле не будет содержать никакого слона. И цена за него будет соответствующая: как за кота.

Завершим подготовку запроса:
 $session  = curl_init($endpoint);                       
	    curl_setopt($session, CURLOPT_POST, true);              
	    curl_setopt($session, CURLOPT_POSTFIELDS, $xmlRequest); 
	    curl_setopt($session, CURLOPT_RETURNTRANSFER, true);    
	    curl_setopt($session, CURLOPT_HTTPHEADER, $headers);
	    $responseXML = curl_exec($session);
	    curl_close($session);
?>


Настало время отправить наш запрос…
<?php
header('X-Accel-Buffering: no');
ob_get_flush();

$responseXML = Ebay_shopping::findItemsAdvanced('cobra exhaust c90t'); 
	// "cobra exhaust c90t" — это значит "глушитель марки Cobra для мотоцикла Suzuku Boulevard C90T". Если вы вставите в запрос "iPhone", то в этой категории вы не найдете ни одного айфона: вам будет нужно указать <categoryId>9355</categoryId>.

$responseXML = simplexml_load_string($responseXML); 
print_r($responseXML);
?>

… и получить ответ:
Он длинный...
SimpleXMLElement Object
(
    [ack] => Success
    [version] => 1.13.0
    [timestamp] => 2014-11-24T18:01:37.836Z
    [searchResult] => SimpleXMLElement Object
        (
            [@attributes] => Array
                (
                    [count] => 11 // всего найдено 11 лотов, мы разберем один
                )

            [item] => Array
                (
                      [0] => SimpleXMLElement Object
                        (
                            [itemId] => 360763537259 
// номер лота, уникальный идентификатор товара. Его можно вставить в строку поиска на сайте eBay или передать другу вместо огромной ссылки, которую генерит eBay.
                            [title] => Cobra Speedster Exhaust with Powerport Long 2005 Suzuki C90T Boulevard 
// название товара. Именно здесь ищется ваш $request.

                            [globalId] => EBAY-MOTOR // раздел eBay, к которому относится этот лот
                            [primaryCategory] => SimpleXMLElement Object
                                (
                                    [categoryId] => 178001
                                    [categoryName] => Other Exhaust Parts
                                )

                            [galleryURL] => http://thumbs4.ebaystatic.com/m/mbTIInAkeUhM9YV7mV7GtcQ/140.jpg
// маленькая и довольно бесполезная фотка товара. Мы научимся получать большие фотки позднее.

                            [viewItemURL] => http://www.ebay.com/itm/Cobra-Speedster-Exhaust-Powerport-Long-2005-Suzuki-C90T-Boulevard-/360763537259?pt=Motorcycles_Parts_Accessories
// по этому урлу будет доступен этот лот на сайте ebay

                            [paymentMethod] => Array
                                (
                                    [0] => PayPal
                                    [1] => VisaMC
                                    [2] => AmEx
                                    [3] => Discover
                                )

                            [autoPay] => false
                            [postalCode] => 46528
                            [location] => Goshen,IN,USA
                            [country] => US
                            [sellerInfo] => SimpleXMLElement Object
                                (
                                    [sellerUserName] => motored_e 

                                    [feedbackScore] => 11025 // сюда попали только те, у кого FeedbackScoreMin больше 3000
                                    [positiveFeedbackPercent] => 99.1 // ...а вот недобросовестных продавцов мы отфильтруем чуть позже. Здесь эта фича не работает

                                    [feedbackRatingStar] => YellowShooting
                                    [topRatedSeller] => false
                                )

                            [shippingInfo] => SimpleXMLElement Object
                                (
                                    [shippingServiceCost] => 0.0
                                    [shippingType] => FlatDomesticCalculatedInternational
                                    [shipToLocations] => Worldwide
                                    [expeditedShipping] => true
                                    [oneDayShippingAvailable] => false
                                    [handlingTime] => 1
                                )

                            [sellingStatus] => SimpleXMLElement Object
                                (
                                    [currentPrice] => 521.51
                                    [convertedCurrentPrice] => 521.51
                                    [sellingState] => Active
                                    [timeLeft] => P11DT9H1M57S
                                )

                            [listingInfo] => SimpleXMLElement Object
                                (
                                    [bestOfferEnabled] => false
                                    [buyItNowAvailable] => false
                                    [startTime] => 2013-10-12T02:58:34.000Z
                                    [endTime] => 2014-12-06T03:03:34.000Z
                                    [listingType] => FixedPrice
                                    [gift] => false
                                )

                            [returnsAccepted] => true
                            [condition] => SimpleXMLElement Object
                                (
                                    [conditionId] => 1000 // хотелось бы в запросе указывать "1000" вместо "New"... но увы, не работает
                                    [conditionDisplayName] => New
                                )

                            [isMultiVariationListing] => false
                            [topRatedListing] => false
                        )

                )

        )

    [paginationOutput] => SimpleXMLElement Object
        (
            [pageNumber] => 1
            [entriesPerPage] => 100
            [totalPages] => 1
            [totalEntries] => 11
        )

    [itemSearchURL] => http://www.ebay.com/sch/10063/i.html?_sasl=riderswarehouse&payment=PayPal&_fss=1&LH_SpecificSeller=1&LH_PayPal=1&_nkw=cobra+exhaust+c90t&LH_BIN=1&LH_ItemCondition=1&_saslop=2&LH_AvailTo=1&_fblo=3000&_fbsc=1&_fls=1&_incaucbin=0&_ipg=100&_os=S%7CD&_pgn=1&_saact=168&_sop=15
// этот урл будет в строке браузера, если мы будем искать наш $request на сайте ebay

)



Хотелось бы остановиться на некоторых моментах ответа.
[shipToLocations] => Worldwide
Эта стока на самом деле ни о чем не говорит. Если продавец вручную ввел вашу страну в черный список, и ни за какие деньги не собирается отправлять туда свои товары, то в этом месте ответа точно так же будет красоваться Worldwide.

[convertedCurrentPrice] => 521.51
EBay API может выдавать нам цены в той валюте, в которой их выставил продавец. На практике правильнее привести все цены в доллары, и этим занимается как раз эта строка.

[timeLeft] => P11DT9H1M57S
По истечению этого времени лот протухнет и будет перевыставлен (Item Relisted). Через некоторое врмя мы больше не сможем найти его по itemID.

[entriesPerPage] => 100
[totalPages] => 1

В eBay API существует глобальное ограничение в 100 лотов на страницу. Если по вашему запросу нашлось больше, вам придется делать несколько запросов и сшивать ответы воедино. В eBay API нет такой функции и мы напишем ее позже.

С полученным ответом вы уже можете что-нибудь сделать и наверняка у вас это получится лучше. Если эта статья будет интересна хаброчитателям, в следующей мы разберем, как его обрабатываю я и что из этого получается.

Также мы рассмотрим возможный алгоритм комбинирования нескольких функций eBay API «из жизни», скормим результат работы одной функции на вход другой, применим несколько фильтров и получим на выходе результат, достойный записи в вашу базу.
Удачи.
Tags:
Hubs:
+1
Comments5

Articles