Реалізація імпорту товарів з YML-фіду (формат Яндекс.Маркет)

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація імпорту товарів з YML-фіду (формат Яндекс.Маркет)
Середня
~3-5 робочих днів
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Реалізація імпорту товарів з YML-фіду (формат Яндекс.Маркету)

YML (Yandex Market Language) — XML-схема, яку постачальники готують для розміщення на Яндекс.Маркеті. Для інтернет-магазину це безцінне джерело: структуровані дані з цінами, залишками, характеристиками та зображеннями, вже перевірені постачальником.

Структура YML-фіду

<?xml version="1.0" encoding="UTF-8"?>
<yml_catalog date="2024-01-15 10:00">
  <shop>
    <name>Магазин постачальника</name>
    <currencies>
      <currency id="RUR" rate="1"/>
    </currencies>
    <categories>
      <category id="10">Електроніка</category>
      <category id="11" parentId="10">Смартфони</category>
    </categories>
    <offers>
      <offer id="ABC-123" available="true">
        <name>Смартфон Example Pro 128GB</name>
        <price>29990</price>
        <oldprice>34990</oldprice>
        <currencyId>RUR</currencyId>
        <categoryId>11</categoryId>
        <picture>https://cdn.supplier.ru/images/ABC-123_1.jpg</picture>
        <vendor>Example</vendor>
        <vendorCode>PRO128</vendorCode>
        <description><![CDATA[Детальний опис...]]></description>
        <param name="Екран" unit="дюйм">6.7</param>
      </offer>
    </offers>
  </shop>
</yml_catalog>

Потоковий парсер

Великі фіди можуть перевищувати 500 МБ — SimpleXML::load() вбиває PHP. Паримо через XMLReader:

class YmlFeedParser
{
    public function parse(string $url): iterable
    {
        $reader = new \XMLReader();
        $reader->open($url, null, LIBXML_NOERROR);

        // Спочатку збираємо категорії (вони на початку)
        $categories = $this->parseCategories($reader);

        // Потім ітеруємо offers
        while ($reader->read()) {
            if ($reader->nodeType === \XMLReader::ELEMENT && $reader->name === 'offer') {
                $node = new \SimpleXMLElement($reader->readOuterXml());
                yield $this->parseOffer($node, $categories);
            }
        }
        $reader->close();
    }

    private function parseOffer(\SimpleXMLElement $node, array $categories): array
    {
        $categoryId   = (string) $node->categoryId;
        $categoryPath = $this->buildCategoryPath($categoryId, $categories);

        return [
            'sku'           => (string) $node['id'],
            'available'     => ((string) $node['available']) === 'true',
            'name'          => (string) $node->name,
            'price'         => (float)  $node->price,
            'old_price'     => $node->oldprice ? (float) $node->oldprice : null,
            'currency'      => (string) $node->currencyId,
            'category_path' => $categoryPath,
            'images'        => array_map(fn($pic) => (string) $pic, $node->picture),
            'vendor'        => (string) $node->vendor,
            'description'   => (string) $node->description,
        ];
    }
}

Валідація та кешування

class YmlFeedValidator
{
    public function validate(string $url): ValidationResult
    {
        // Перевірка DTD
        libxml_use_internal_errors(true);
        $dom = new \DOMDocument();
        $dom->load($url);
        $xmlErrors = libxml_get_errors();
        libxml_clear_errors();

        foreach ($xmlErrors as $error) {
            $errors[] = "XML error at line {$error->line}: {$error->message}";
        }

        // Перевірка обов'язкових елементів
        $xpath = new \DOMXPath($dom);
        if (!$xpath->query('//offers/offer')->length) {
            $errors[] = 'No offers found in feed';
        }

        return new ValidationResult(empty($errors), $errors);
    }
}

Job імпорту

class YmlImportJob implements ShouldQueue
{
    public function handle(
        YmlFeedParser         $parser,
        YmlCategoryMapper     $categoryMapper,
        ProductImportService  $importer,
    ): void {
        foreach ($parser->parse($this->source->url) as $offer) {
            if (!$offer['available']) {
                $importer->markUnavailable($offer['sku'], $this->source->id);
                continue;
            }

            $siteCategoryId = $categoryMapper->resolve(
                $offer['category_id'],
                $offer['category_path'],
                $this->source->id
            );

            $importer->upsert(array_merge($offer, [
                'site_category_id' => $siteCategoryId,
                'source_id'        => $this->source->id,
            ]));
        }
    }
}

Тривалість реалізації

  • Потоковий парсер YML, базовий імпорт цін/залишків/описів — 2 дні
  • Маппінг категорій, конвертація валют, зображення — +1 день
  • Валідація фіду, кешування, scheduler, логування — +1 день