{"id":14275,"url":"\/distributions\/14275\/click?bit=1&hash=bccbaeb320d3784aa2d1badbee38ca8d11406e8938daaca7e74be177682eb28b","title":"\u041d\u0430 \u0447\u0451\u043c \u0437\u0430\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442 \u043f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u043e\u0434\u0430\u0432\u0446\u044b \u0430\u0432\u0442\u043e?","buttonText":"\u0423\u0437\u043d\u0430\u0442\u044c","imageUuid":"f72066c6-8459-501b-aea6-770cd3ac60a6"}

Как продавать через «Яндекс.Маркет» и не остаться без штанов (личный опыт и PHP-скрипт)

Как я и обещал в своей статье, продолжаю делиться опытом и разработками. Сегодня расскажу, как правильно загружать товары на «Яндекс.Маркет», чтобы увеличить количество трафика без увеличения ставок. Как назначать ставки на конкретные товары, с учётом конверсии и наценки в автоматическом режиме.

Зажравшиеся барыги

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

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

Кто же тогда получает сверхприбыли, продавая втридорога иностранные товары?

В российской интернет-торговле два основных получателя прибыли: государство (налоги, таможенные пошлины и банковские проценты составляют до половины стоимости товара) и поставщики трафика («Яндекс» преимущественно).

В отрасли сложилась устойчивая практика, когда необходимо отдавать «Маркету» как минимум всю наценку, чтобы получить клиента, и надеяться на то, что он станет постоянным клиентом и начнет приносить чистую прибыль.

«Яндекс.Маркет» годами совершенствует свои алгоритмы, чтобы выжать продавца до последней копейки, чего стоит один только «Яндекс.Советник», который успешно продает одного клиента нескольким магазинам.

Поведение «Яндекс.Маркета» объяснимо, он строит свой собственный екоммерс-проект — «Беру». Малые и средние интернет-магазины для него не долгосрочные партнеры, а временный ресурс, который нужно максимально выжать в пользу своего проекта. Одним выстрелом он убивает двух зайцев, обескровливает конкурентов «Беру» и аккумулирует ресурсы для его развития.

Что делать?

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

Отдавать всю наценку «Маркету» за заказ и надеяться, что покупатель за новым заказом не пойдет обратно на «Маркет», а станет вашим постоянным клиентом, так себе идея, решать вам.

Для себя я решил, что пока готов отдавать всю наценку «Маркету», так как какая-то часть клиентов с него в итоге стала моими постоянными покупателями. Вероятность того, что клиент с «Маркета» станет вашим постоянным клиентом, зависит от уникальности вашего ассортимента и качества сервиса.

В этой рискованной стратегии необходимо быть уверенным в том, что ты отдаешь именно наценку, а не кратно больше (можно и больше, но это должно быть сознательным решением), что ты получаешь реальных клиентов, а не нерелевантный трафик.

Необходимо держать руку на пульсе по каждому товару, размещенному на «Маркете». Регулярно подсчитывать его конверсию, фактор сезонности и смену моды. Необходимо понимать, сколько вы готовы платить «Маркету» за клик по конкретному товару, чтобы не остаться и без денег, и без клиентов.

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

Я, например, заметил большое влияние на конверсию распродажи «11.11» («день холостяка» на «Алиэкспрессе»). За неделю до неё конверсия по всем товарам резко падает, приходится кратно снижать ставки на «Маркете» на все позиции.

Российские распродажи («черная пятница» и «кибер-понедельник») не оказывают серьезного влияния на конверсию. Это говорит о том, что россияне больше интересуются китайской распродажей, активно перепроверяют цены, в том числе на аналоги, много кликают — мало покупают.

Почему я стал «изобретать велосипед»?

Для подсчета конверсии есть «Яндекс.Метрика» и Google Analytics. Для управления ставками есть яндексовский Pricelabs.

Pricelabs можно связать с «Яндекс.Метрикой» для передачи ему конверсии конкретных товаров. Через XML можно передать в «Яндекс.Маркет» свои закупочные цены, с помощью которых в Pricelabs возможно использовать стратегию управления ставками — чтобы стоимость заказа не превышала определенный вами процент от наценки (по умолчанию стоит 100%).

Казалось бы, живи и радуйся, настроил все и спи спокойно, дорогой товарищ...

Я никогда не доверяю одному источнику информации (тем более аффилированному с продавцом трафика), всегда перепроверяю цифры.

Для подсчета ROI у меня имеется собственный PHP-скрипт, который постоянно мне показывал, что «Яндекс.Маркет» уходит в минус, то есть потребляет больше денег, чем даёт прибыли с заказов, поставленных им.

Что я только ни пробовал, как только ни играл с настройками Pricelabs, результат один и тот же, «Маркет» все равно уходит в минус. То ли руки у меня кривые, то ли заговор... Pricelabs изначально был независимым проектом, «Яндекс» купил его в 2014 году.

Возможно, не будь я программистом, я бы и дальше мучился с настройками Pricelabs до посинения и тогда этой статьи не было бы. Но нам, программистам, без трудностей нельзя, собрался с духом и написал свой Pricelabs, как сказал бы мне любой коллега — изобрел велосипед. Я рад, что сделал это, так как работу собственного велосипеда я понимаю и контролирую.

С помощью своего «велосипеда» я смог заставить «Яндекс.Маркет» поставлять мне клиентов по приемлемой для меня цене.

Денис Демидов, типа программист

Конструкция «велосипеда»

Все начинается с правильной загрузки товаров на «Яндекс.Маркет». Практически у всех известных CRM для интернет-магазинов есть модули для создания XML-файла в формате «Яндекс.Маркета», но я не видел ни одного модуля, где бы XML формировался наиболее полно и правильно с точки зрения требований самого «Яндекс.Маркета».

Далее необходимо фиксировать трафик с «Маркета» для подсчета конверсии по каждому товару.

После того как вы рассчитали конверсию, необходимо с помощью API «Яндекс.Маркета» передать ему размер максимальной ставки по каждому товару для аукциона, то есть сколько вы готовы заплатить за клик, чтобы быть выше конкурента.

Как правильно загружать товары на «Яндекс.Маркет»?

Главный нюанс заключается в том, что структура каталога и название категорий должны быть в точности как на «Маркете», иначе ваши товары не только не попадут на карточку товара, но и на поиск могут не попасть, несмотря на то, что в названии вашего товара есть слова, по которым ищет пользователь. Категории «Маркета» необходимо взять по ссылке.

Скорее всего, названия категорий на вашем сайте не совпадают с названиями «Маркета», как и у меня. У меня — для решения этого вопроса — категории имеют два названия: для сайта и для «Маркета».

В идеале, как рекомендует «Яндекс.Маркет», ещё и элемент typePrefix (Тип/категория товара) должен содержать слова из их каталога.

Так как этот элемент используется в формировании общего названия товара на «Маркете» (typePrefix + vendor + model), могут случиться ошибки, если вы будете делать это на автомате, вы рискуете ввести клиента в заблуждение.

Обязательно используйте элемент <param>:

Таким образом ваши товары смогут участвовать в выдаче при использовании клиентом фильтра «Маркета» по товарам, это даст дополнительный трафик без увеличения ставки. Помните, передавать нужно только параметры, которые есть в фильтре самого «Маркета». Используйте именно эти названия параметров фильтра в вашей товарной категории.

Разработчики «Яндекса» уверяют, что они анализируют описание товара даже если не переданы элементы, но как показывает мой опыт, чем точнее и полнее будут передаваемые вами данные в «Маркет», тем больше будет у вас трафика без увеличения ставки.

Если у вас не более тысячи товаров, то можно вручную заполнить характеристики в своей базе. Если у вас есть собственный фильтр на сайте, возьмите его данные. Я беру данные для фильтра «Маркета» из названия и описания товаров.

Считаем конверсию

Посчитать конверсию не трудно. Необходимо записывать в базу каждый клик с «Маркета», клиенту поставить Cookie, что он пришел с «Маркета», с временем жизни десять дней, это примерный срок в течение которого человек выбирает и покупает товар.

В момент оформления заказа необходимо проверить, установлена ли маркетовская cookie, если да, то в заказе это нужно отметить, чтобы потом можно было подсчитать конверсию, то есть сколько заказов приходится на 100 переходов с «Маркета».

По каждому товару необходимо регулярно пересчитывать конверсию и записывать ее в таблицу товаров, так как вычислять на лету, при непосредственной передаче ставки в «Маркет», нереально, слишком «тяжелый» получится скрипт.

Если переходов с «Маркета» по конкретному товару менее 100 в месяц (квартал), то используйте для товара среднюю конверсию либо по бренду, либо по категории, либо по поставщику.

Назначаем ставку через API «Яндекс.Маркета»

Все довольно просто, регистрируемся на OAuth-сервере «Яндекса», чтобы получить идентификатор и авторизационный токен для работы с API «Яндекс.Маркета», подробнее:

Полученные данные вставляем в PHP-скрипт:

define("TOKEN", "***************************************"); define("CLIENT_ID", "********************************"); define("CAMPAIGN_ID", "*******"); define("PRICE_LIST_ID", "****"); define("PASSWORD", "********************************");

Отправку ставок в «Маркет» я объединил с формированием XML-файла. В личном кабинете «Маркета» не забываем включить источник ставок через API по ID товара.

Ограничьте дневной бюджет на «Маркете», чтобы случайная ошибка не съела все ваши деньги.

Инсталляция

Скачиваем дистрибутив, да простят меня профессиональные разработчики, что ссылка не на GitHub и что устанавливать надо ручками, а не через Composer. Возможно, когда-нибудь я созрею выложить все скрипты AvtoGSM.ru в открытый доступ на GitHub.

Скачанный market.php загружаем в корневую категорию вашего сайта. Добавляем данные для доступа к вашей базе данных и информацию о магазине:

define('DB_HOST', '***.mysql.masterhost.ru'); // database host define('DB_USER', '***'); // username define('DB_PASS', '***'); // password define('DB_NAME', '***'); // database name define ("NAME_SHOP", "AvtoGSM.ru"); define ("NAME_LLC", "ООО 'АвтоДжиЭсЭм'"); define ("URL_SHOP", "https://avtogsm.ru");

В index.php вставляем следующий код:

// переход с маркета if (isset($_GET["from"]) && $_GET["from"]=="ya") { $_SESSION["from_user"]="market"; setcookie("mr", 1, time() + 864000); $source_rekl="mr"; } // назначаем уникальный id посетителю если его нет if (isset($_COOKIE['log_ids']) && $_COOKIE['log_ids'] > 0) setcookie('log_ids', $_COOKIE['log_ids'], time() + 31536000); elseif (stripos(getenv("HTTP_USER_AGENT"),"bot")===FALSE) { // получаем уникальный код mysql_query("INSERT INTO `log_config` (`from`) VALUES ('".getenv("HTTP_REFERER")."')"); $id = mysql_insert_id(); mysql_query("TRUNCATE TABLE `log_config`"); setcookie('log_ids', $id, time() + 31536000); } // Пишем статистику для расчета конверсии if (isset($_COOKIE['log_ids']) || $source_rekl!="") mysql_query("INSERT INTO log_user_travel_product (idUser, idProduct, date, source_rekl, zoneID) VALUES ('".(int)$_COOKIE['log_ids']."', '".(int)$_GET["productID"]."', NOW(), '".$source_rekl."', '".$zoneID."')");

Через phpmyadmin создаем таблицу для хранения кликов с «Маркета»:

CREATE TABLE `log_user_travel_product` ( `id` int(11) NOT NULL, `idUser` bigint(11) DEFAULT NULL, `idProduct` mediumint(11) DEFAULT NULL, `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `source_rekl` varchar(2) NOT NULL, `zoneID` smallint(11) NOT NULL ) ENGINE=MyISAM AVG_ROW_LENGTH=28 DEFAULT CHARSET=cp1251; ALTER TABLE `log_user_travel_product` ADD PRIMARY KEY (`id`), ADD KEY `idUser` (`idUser`), ADD KEY `idProduct` (`idProduct`), ADD KEY `date` (`date`), ADD KEY `source_rekl` (`source_rekl`); ALTER TABLE `log_user_travel_product` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=17970627; COMMIT; CREATE TABLE `log_config` ( `id` bigint(11) NOT NULL ) ENGINE=MyISAM AVG_ROW_LENGTH=7 DEFAULT CHARSET=cp1251;

В вашей таблице заказов создаете поле marketing (varchar 50 символов), где будут храниться метки источников трафика, откуда к вам приходил человек, пока не сделал заказ.

В таблице товаров создаете поле conversion (float), где будет храниться конверсия этого товара.

В том месте вашего кода, где создается запись в таблицу с новыми заказом, вставляете этот код:

$marketing = $_SESSION["from_user"]." "; foreach ($_COOKIE as $key=>$val) if (strlen($key) < 5 && $val > 0) $marketing.=$key.":".(int)$val; db_query( "update orders set marketing = '".$marketing ."' where orderID ='".$orderID."'" );

Настраиваете CRON для автоматического запуска создания XML, выгрузки ставок и для пересчета конверсий. Пример записи для хостинга Mastehost (запускаемся раз в час в рабочее время):

1 10-18 * * * /usr/bin/GET https://avtogsm.ru/market.php?yandex=1 5 10-18 * * * /usr/bin/GET https://avtogsm.ru/market.php?conversion=mr

Бонусы

В данном скрипте есть функциональность для создания XML для Google Shopping (market.php?google=yes). Но никак руки не дойдут для написания аналогичного скрипта назначения ставок в Google Shopping, так как он в минуса у меня еще никогда не уходил, один раз назначил ставку вручную для всех товаров и забыл.

Вероятно конкуренция там пока существенно меньше, да и никаких «советников», пытающихся одного клиента продать нескольким магазинам, там нет.

Там же есть код выгрузки точек самовывоза (например СДЕК) в «Яндекс.Маркет» (market.php?addpvz=yes).

P.S.

Подписывайте на меня, как автора, чтобы не пропустить следующие статьи, в которых я планирую выложить PHP-скрипты и расписать работу следующих подсистем AvtoGSM.ru:

  • Создание email-рассылки и отправка через Amazon SES в полуавтоматическом режиме.
  • Складская система + заказ поставщикам.
  • Система «умной» рекомендации товаров.
  • Отслеживание местонахождения отправлений «Почты России» и СДЭК (оповещение о прибытии и просьба написать отзыв после вручения заказа).
  • Cкрипт маркетплейса.
0
122 комментария
Написать комментарий...
Peter M.

С точки зрения информационной безопасности категорически не стоит использовать эти коды без полного ревью и/или переписывания адекватным программистом.

Автору: ваш магазин еще жив? Надеюсь у вас есть резервные копии всего. Советую полностью закрыть магазин от какого-либо внешнего влияния и заниматься только поиском и устранением уязвимостей.

Почему? А посмотрите что например там есть:
mysql_query("INSERT INTO `log_config` (`from`) VALUES ('".getenv("HTTP_REFERER")."')");
(примитивная SQL-инъекция, позволяет кому угодно в сети получить доступ к вашей базе данных)

Ответить
Развернуть ветку
Денис Демидов
Автор

Нормальные сайты имеют дополнительно модуль, которые выискивает во входящих данных (get, post, куки) все подозрительное и режут его. Запускается этот модуль в самом начале работы скрипта.
Конкретно этот файл можно и нужно закрыть в эксессе от внешнего воздействия, так как он 100% внутренняя инфраструктура, а не клиентская часть.
Конкретно эту строку надо поменять на 
mysql_query("INSERT INTO `log_config` (`from`) VALUES ('1')");

Ответить
Развернуть ветку
Peter M.

"Нормальные сайты" избавляются от уязвимостей в коде и не надеются на сторонние фильтрации, которые кстати никогда не решат вопрос на 100%.
https://ru.stackoverflow.com/questions/524775/%D0%9A%D0%BE%D0%B3%D0%B4%D0%B0-%D0%BD%D1%83%D0%B6%D0%BD%D0%BE-%D0%B4%D0%B5%D0%BB%D0%B0%D1%82%D1%8C-%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85

Конкретно этот код вы предлагаете вставить в index.php сайта, очевидно он будет выполняться для каждого пользователя, непонятно как можно ограничивать к нему доступ.

Если вам не нужны данные о рефере, то конечно можно заменить и на '1'. Но если все-таки нужны, то нужно правильно экранировать сохраняемые в базу данные:
mysql_query("INSERT INTO `log_config` (`from`) VALUES ('".mysql_real_escape_string(getenv("HTTP_REFERER"))."')");

(на самом деле в настоящее время также нельзя использовать функции mysql_* и PHP5 в целом, разработчики прекратили их поддержку, они сами по себе потенциальные уязвимости)

Это самые основы программирования на PHP.

Ответить
Развернуть ветку
Денис Демидов
Автор
которые кстати никогда не решат вопрос на 100%.
на самом деле в настоящее время также нельзя использовать функции mysql_* и PHP5 в целом

Вот вы сами себе и ответили, что нет 100% решения вопроса.

Ответить
Развернуть ветку
Peter M.

Хм, ничего подобного я не говорил. И 100% решение обеих проблем есть.

1 - написание безопасного кода. Данные, сохраняемые в базу, нужно экранировать. Именно это я показал в примере функцией mysql_real_escape_string. Это 100% решение вопроса: что бы ни пришло в реферере, оно будет сохранено как текст и никогда не будет интерпретировано как SQL.

2 - использование актуального ПО. PHP5 и функции mysql_* устарели, не поддерживаются разработчиками, содержат неисправленные ошибки и уязвимости. Следует использовать PHP 7.2, 7.3, 7.4 и MySQLi или PDO. Это никак не влияет на необходимость думать о безопасном коде, об экранировании данных и прочее. Просто там иные приемы для этого.

Т.е. использование PHP 7.[2-4] и хотя бы MySQLi на 100% решает обе проблемы. Рассматриваемая строка кода в таком случае должна выглядеть примерно так:
mysqli_query($db, "INSERT INTO `log_config` (`from`) VALUES ('".mysqli_real_escape_string($db, getenv("HTTP_REFERER"))."')");

Это тоже не идеал по современным меркам, но по крайней мере не создает проблем безопасности и ошибок.

Ответить
Развернуть ветку
Денис Демидов
Автор

В строке .mysqli_real_escape_string($db, getenv("HTTP_REFERER"))
Вы аргументы местами перепутали
http://www.php.su/mysql_real_escape_string

Какая именно конструкция в данном примере является идеалом по современным меркам?

Ответить
Развернуть ветку
Peter M.

Нет, не перепутал. Но вы перепутали, даже ссылку не на ту функцию дали :) Вот верная: https://www.php.net/manual/en/mysqli.real-escape-string.php

Идеал наверное у каждого свой.
Привлекать полноценную ORM в данном случае это лишнее, можно использовать PDO или какой-нибудь простенький SQL-builder (ну мне они просто нравятся :) ). MySQLi слишком низкоуровневый, пожалуй даже в простых случаях не стоит.
Поэтому наверное самым оптимальным вариантом будет PDO с prepared statements.
https://www.php.net/manual/en/pdo.prepared-statements.php

Ответить
Развернуть ветку
Денис Демидов
Автор

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

Ответить
Развернуть ветку
119 комментариев
Раскрывать всегда