Автоматизируйте маркетинговое исследование: как парсить Shopify с помощью Python

Последнее обновление: April 16, 2026
Автоматизируйте маркетинговое исследование: как парсить Shopify с помощью Python

Эндпоинт Shopify /products.json — один из самых недооценённых секретов в e-commerce данных. Просто добавьте его к URL любого магазина на Shopify, и вы получите структурированный JSON без API-ключей, без авторизации и без разбора сложного вложенного HTML.

Я работаю в команде Thunderbit Official Website, поэтому много думаю о том, как люди собирают данные из веба. И тема парсинга Shopify всплывает постоянно — команды продаж отслеживают цены конкурентов, операционные специалисты в e-commerce сравнивают каталоги товаров, закупщики ищут новых поставщиков. С 4.82 миллиона активных продавцов на Shopify и долей платформы около 30% рынка e-commerce в США, объём доступных для сбора товарных данных огромен.

В этом руководстве я разберу весь процесс: что возвращает этот эндпоинт, как проходить по тысячам товаров с пагинацией, как не упереться в лимиты запросов и не получить блокировку, а также как превратить вложенный JSON Shopify в аккуратный CSV или Excel-файл с помощью pandas. Я также покажу другие эндпоинты, о которых почти никто не говорит (/collections.json, /meta.json), и предложу no-code альтернативу для тех, кто не хочет использовать Python.

Что такое эндпоинт Shopify /products.json и почему он так упрощает парсинг

У каждого магазина на Shopify есть публичный эндпоинт {store-url}/products.json, который возвращает структурированные данные о товарах. Никаких API-ключей. Никакого OAuth. Вообще никакой авторизации. Достаточно добавить /products.json к адресу магазина — и вы получите JSON-массив со всеми товарами каталога.

Проверьте прямо сейчас: откройте allbirds.com/products.json или zoologistperfumes.com/products.json в браузере. Вы увидите чистый, структурированный JSON с названиями товаров, ценами, вариантами, изображениями, тегами — всем нужным.

А теперь сравните это с альтернативой: разбор HTML-шаблонов Shopify, которые глубоко вложены, в каждом магазине отличаются и меняются при каждом обновлении темы. Вот с чем обычно приходится работать:

Подход через HTML (больно):

<div class="product-card__info">
  <h3 class="product-card__title">
    <a href="/products/classic-blue-jeans">Classic Blue Jeans</a>
  </h3>
  <span class="price price--on-sale" data-product-price>$149.00</span>
</div>

Подход через JSON (аккуратно):

{
  "title": "Classic Blue Jeans",
  "handle": "classic-blue-jeans",
  "vendor": "Hiut Denim",
  "variants": [{"price": "149.00", "sku": "HD-BLU-32", "available": true}]
}

JSON выигрывает по стабильности, надёжности и простоте обработки. Эндпоинт также поддерживает два ключевых параметра запроса — ?limit= (до 250 товаров на страницу, по умолчанию 30) и ?page= для пагинации — и мы активно будем использовать их в коде ниже.

Важное различие: это публичный storefront-эндпоинт, а не Shopify Admin API. Admin API требует токены доступа владельца магазина и даёт данные о заказах, остатках и клиентах. Публичный /products.json — это только данные о товарах в режиме чтения, доступные любому. Ниже я подробно объясню разницу, потому что на форумах вокруг этого постоянно возникает путаница.

Оговорка: не у каждого магазина на Shopify открыт этот эндпоинт. По моим тестам, примерно 71% магазинов возвращают валидный JSON (allbirds.com, gymshark.com, colourpop.com, kyliecosmetics.com — всё работает), а у некоторых кастомных конфигураций приходит 404 (hiutdenim.co.uk, bombas.com). Быстрая проверка простая: откройте {store-url}/products.json в браузере и посмотрите результат.

Зачем парсить Shopify на Python? Основные бизнес-сценарии

Зачем вообще этим заниматься? Из-за ROI. Сейчас 81% ритейлеров в США используют автоматический сбор цен для конкурентной аналитики, тогда как в 2020 году таких было всего 34%. Исследования также показывают, что улучшение ценовой стратегии всего на 1% даёт в среднем рост прибыли на 11.1%. Эти данные действительно стоят денег.

Вот самые частые сценарии, с которыми я сталкиваюсь:

СценарийКому полезноЧто вы получаете
Мониторинг цен конкурентовКоманды ecommerce-операцийОтслеживание изменений цен, скидок и compare-at price по каталогам конкурентов
Исследование товаров и поиск поставщиковЗакупки / мерчандайзингСравнение характеристик, вариантов, материалов и наличия товаров
Генерация лидовОтделы продажИзвлечение названий поставщиков, брендов и контактных данных из каталогов магазинов
Анализ рынка и категорииКоманды маркетингаПонимание ассортимента, тегов, структуры коллекций и позиционирования
Отслеживание запасов и наличияКоманды supply chainМониторинг статуса наличия на уровне вариантов (available: true/false) во времени
Обнаружение новых товаровПродуктовые командыОтслеживание created_at, чтобы замечать новые запуски у конкурентов

Python здесь подходит идеально. 69.6% разработчиков, занимающихся парсингом, используют Python как основной язык, а экосистема — requests для HTTP, pandas для обработки данных, httpx для асинхронных запросов — позволяет довольно быстро пройти путь от «у меня есть URL» до «у меня есть таблица» менее чем за 80 строк кода.

Полный справочник по полям products.json: что означает каждое поле

В большинстве статей показывают только title, id и handle, а потом сразу переходят к коду. Но JSON-ответ Shopify содержит более 40 полей на уровне товаров, вариантов, изображений и опций. Если заранее знать, что доступно, вы сэкономите себе повторный сбор данных позже.

Я собрал этот справочник на основе живых ответов /products.json, полученных 16 апреля 2026 года. Структура одинакова для всех магазинов, у которых этот эндпоинт открыт.

Поля на уровне товара

ПолеТип данныхПримерБизнес-применение
idЦелое число123456789Уникальный идентификатор товара для дедупликации
titleСтрока"Classic Blue Jeans"Название товара для каталогов и сравнений
handleСтрока"classic-blue-jeans"URL-слуг — ссылку на страницу товара можно собрать как {store}/products/{handle}
body_htmlСтрока (HTML) или null

Our best-selling...

Описание товара для контент-анализа и SEO-исследований
vendorСтрока"Hiut Denim"Название бренда/поставщика для генерации лидов или поиска поставщиков
product_typeСтрока"Jeans"Категоризация товара для анализа рынка
created_atISO DateTime"2024-01-15T10:30:00-05:00"Отслеживание даты добавления товара (для выявления новых запусков)
updated_atISO DateTime"2025-03-01T08:00:00-05:00"Выявление недавних изменений в каталоге
published_atISO DateTime"2024-01-16T00:00:00-05:00"Понимание, когда товар стал доступен на витрине
tagsМассив строк["organic", "women", "straight-leg"]Анализ тегов и ключевых слов для SEO, категоризации и поиска трендов
variantsМассив объектов(см. поля вариантов ниже)Цена, SKU и доступность по каждому варианту
imagesМассив объектов(см. поля изображений ниже)URL изображений товаров для каталогов и визуального анализа
optionsМассив объектов[{"name": "Size", "values": ["S","M","L"]}]Понимание конфигурации товара (размер, цвет, материал)

Поля на уровне варианта (вложены в каждый товар)

ПолеТип данныхПримерСценарий использования
idЦелое число987654321Уникальный идентификатор варианта
titleСтрока"32 / Blue"Отображаемое название варианта
skuСтрока"HD-BLU-32"Сопоставление SKU для складских систем
priceСтрока"185.00"Мониторинг цен (обратите внимание: это строка, для расчётов нужно преобразовать в float)
compare_at_priceСтрока или null"200.00"Исходная цена — критично для отслеживания скидок
availableЛогический типtrueНаличие на складе (единственный публичный индикатор запасов)
weightЧисло с плавающей точкой1.2Анализ доставки и логистики
option1, option2, option3Строка"32", "Blue", nullЗначения отдельных опций
created_at, updated_atISO DateTimeОтслеживание изменений на уровне варианта

Поля на уровне изображения

ПолеТип данныхПримерСценарий использования
idЦелое число111222333Уникальный идентификатор изображения
srcСтрока (URL)"https://cdn.shopify.com/..."Прямая ссылка для скачивания изображения
altСтрока или null"Front view of jeans"Alt-текст изображения для анализа доступности
positionЦелое число1Порядок изображения
width, heightЦелое число2048, 2048Размеры изображения

Чего нет в публичном эндпоинте

Важный нюанс: inventory_quantity отсутствует в публичных ответах /products.json. Это поле было убрано из публичных JSON-эндпоинтов в декабре 2017 года по соображениям безопасности. Единственный индикатор запасов, который вы получаете, — это булево поле available у каждого варианта (true или false). Чтобы получить реальные остатки, нужен авторизованный Admin API с доступом владельца магазина.

Перед тем как писать код парсинга, посмотрите на эту таблицу и решите, какие поля важны именно для вашей задачи. Если вы отслеживаете цены, вам нужны variants[].price, variants[].compare_at_price и variants[].available. Если вы ищете лиды, делайте упор на vendor, product_type и tags. Фильтруйте данные сразу — CSV получится намного чище.

Помимо products.json: коллекции, meta и другие эндпоинты Shopify

Ни одна похожая статья не упоминает эти эндпоинты. А для серьёзной конкурентной аналитики они очень полезны.

/collections.json — все категории магазина

Возвращает все коллекции (категории) магазина с названиями, handle, описаниями и количеством товаров. Я проверил это на zoologistperfumes.com, allbirds.com и gymshark.com — везде вернулся валидный JSON.

{
  "collections": [
    {
      "id": 308387348539,
      "title": "Attars",
      "handle": "attars",
      "published_at": "2026-03-29T12:20:32-04:00",
      "products_count": 1,
      "image": { "src": "https://cdn.shopify.com/..." }
    }
  ]
}

Хотите понять, как конкурент структурирует свой каталог? Вот нужный эндпоинт.

/collections/{handle}/products.json — товары по категории

Возвращает товары, отфильтрованные по конкретной коллекции. Структура JSON такая же, как у /products.json, но только для одной категории. Это особенно важно для парсинга на уровне категорий — например, если вам нужно отслеживать только коллекции конкурента «Sale» или «New Arrivals».

/meta.json — метаданные магазина

Возвращает название магазина, описание, валюту, страну и — что особенно полезно — published_products_count. Это число позволяет заранее точно посчитать, сколько страниц пагинации потребуется: ceil(published_products_count / 250). Больше не нужно вслепую увеличивать номер страницы, пока не получите пустой ответ.

Какой эндпоинт использовать?

| Что вам нужно | Эндпоинт | Нужна авторизация? | |---|---|---|---| | Все товары (публично) | /products.json | Нет | | Товары конкретной категории | /collections/{handle}/products.json | Нет | | Метаданные магазина + количество товаров | /meta.json | Нет | | Все коллекции (категории) | /collections.json | Нет | | Данные о заказах/продажах (только свой магазин) | Admin API /orders.json | Да (API key) | | Количество остатков (только свой магазин) | Admin API /inventory_levels.json | Да |

Частый вопрос на форумах — «Можно ли узнать, сколько единиц продал конкурент?» — имеет короткий ответ: нет. Не через публичные эндпоинты. Данные о продажах и количестве запасов доступны только через авторизованный Admin API, а значит, нужен доступ владельца магазина. Публичные эндпоинты дают только данные каталога товаров.

shopify-data-access-methods.webp

Как парсить Shopify на Python: пошаговая настройка

  • Уровень сложности: Начальный
  • Время: ~15 минут (настройка + первый запуск)
  • Что понадобится: Python 3.11+, pip, терминал и URL магазина Shopify для парсинга

Шаг 1: Установите Python и необходимые библиотеки

Убедитесь, что у вас установлен Python 3.11 или новее (для pandas 3.0.x это обязательно). Затем установите две библиотеки, которые нам понадобятся:

pip install requests pandas

Для экспорта в Excel дополнительно понадобится:

pip install openpyxl

В начале скрипта добавьте такие импорты:

import requests
import pandas as pd
import time
import random
import json

При запуске скрипта не должно быть ошибок импорта. Если pandas ругается на версию, обновите Python до 3.12.

Шаг 2: Получите данные о товарах из /products.json

Вот базовая функция, которая принимает URL магазина, обращается к эндпоинту и возвращает распарсенный JSON:

def fetch_products_page(store_url, page=1, limit=250):
    """Fetch a single page of products from a Shopify store."""
    url = f"{store_url.rstrip('/')}/products.json"
    params = {"limit": limit, "page": page}
    headers = {
        "User-Agent": "Mozilla/5.0 (compatible; ProductResearch/1.0)"
    }
    
    response = requests.get(url, params=params, headers=headers, timeout=30)
    response.raise_for_status()
    return response.json().get("products", [])

Ключевые детали:

  • limit=250 — максимальное значение, которое допускает Shopify на одной странице. По умолчанию 30, так что явная установка этого параметра сокращает число запросов до 8 раз.
  • Заголовок User-Agent: всегда задавайте реалистичный. Запросы без User-Agent чаще срабатывают на антибот-защиту Shopify.
  • timeout=30: один зависший запрос не должен блокировать весь скрипт.

Проверьте на известном магазине:

products = fetch_products_page("https://allbirds.com")
print(f"Fetched {len(products)} products")
print(f"First product: {products[0]['title']}")

Должно получиться что-то вроде: Fetched 250 products и название первого товара.

Шаг 3: Настройте пагинацию, чтобы собрать все товары

Один запрос возвращает максимум 250 товаров. У большинства магазинов товаров больше (у Allbirds — более 1,420). Нужно проходить по страницам, пока не вернётся пустой ответ.

def scrape_all_products(store_url, delay=1.0):
    """Scrape all products from a Shopify store, handling pagination."""
    all_products = []
    page = 1
    
    while True:
        print(f"Fetching page {page}...")
        products = fetch_products_page(store_url, page=page, limit=250)
        
        if not products:
            print(f"No more products. Total: {len(all_products)}")
            break
        
        all_products.extend(products)
        print(f"  Got {len(products)} products (total so far: {len(all_products)})")
        page += 1
        
        # Будьте вежливы: делайте паузу между запросами
        time.sleep(delay + random.uniform(0, 0.5))
    
    return all_products

Когда products возвращается пустым, вы дошли до конца.

time.sleep() с небольшим случайным разбросом помогает не превышать неофициальный лимит Shopify примерно в ~2 запроса в секунду.

Совет: если вы сначала запросите /meta.json, то уже будете знать общее количество товаров и сможете точно рассчитать число страниц: pages = ceil(product_count / 250). Это избавляет от лишнего пустого запроса в конце.

Шаг 4: Разберите данные и оставьте нужные поля

Теперь, когда все товары у вас в виде списка словарей Python, можно оставить только те поля, которые вам нужны. Ниже пример, который вытаскивает самые полезные поля для мониторинга цен:

def extract_product_data(products):
    """Extract key fields from products, flattening variants."""
    rows = []
    for product in products:
        for variant in product.get("variants", []):
            rows.append({
                "product_id": product["id"],
                "title": product["title"],
                "handle": product["handle"],
                "vendor": product.get("vendor", ""),
                "product_type": product.get("product_type", ""),
                "tags": ", ".join(product.get("tags", [])),
                "created_at": product.get("created_at", ""),
                "variant_id": variant["id"],
                "variant_title": variant.get("title", ""),
                "sku": variant.get("sku", ""),
                "price": variant.get("price", ""),
                "compare_at_price": variant.get("compare_at_price", ""),
                "available": variant.get("available", ""),
                "image_url": product["images"][0]["src"] if product.get("images") else ""
            })
    return rows

Так вы получите по одной строке на каждый вариант — это самый удобный формат для сравнения цен, потому что один товар вроде «Classic Blue Jeans» может иметь 12 вариантов (6 размеров × 2 цвета), и у каждого будет своя цена и статус наличия.

Экспорт Shopify-данных в CSV и Excel с помощью pandas

В большинстве других руководств по парсингу Shopify просто сохраняют сырой JSON в файл и считают задачу выполненной. Для разработчиков этого достаточно. Для аналитика e-commerce, которому к пятнице нужна таблица, — бесполезно.

Проблема в том, что JSON Shopify вложенный. Один товар может содержать десяток вариантов, у каждого — своя цена, SKU и наличие. Превратить это в таблицу требует немного работы с pandas.

Преобразуем вложенный JSON в чистую таблицу

Есть два подхода — в зависимости от задачи:

Вариант A: одна строка = один вариант (лучше всего для мониторинга цен и запасов)

# Используем функцию extract_product_data из шага 4
products = scrape_all_products("https://allbirds.com")
rows = extract_product_data(products)
df = pd.DataFrame(rows)

print(f"DataFrame shape: {df.shape}")
print(df.head())

Так вы получите плоскую таблицу, где каждая строка — уникальная комбинация товара и варианта. У магазина с 500 товарами и в среднем 4 вариантами на товар получится DataFrame примерно на 2,000 строк.

Вариант B: одна строка = один товар (лучше для общего обзора каталога)

def summarize_products(products):
    """One row per product with min/max price across variants."""
    rows = []
    for product in products:
        prices = [float(v["price"]) for v in product.get("variants", []) if v.get("price")]
        rows.append({
            "product_id": product["id"],
            "title": product["title"],
            "vendor": product.get("vendor", ""),
            "product_type": product.get("product_type", ""),
            "variant_count": len(product.get("variants", [])),
            "min_price": min(prices) if prices else None,
            "max_price": max(prices) if prices else None,
            "any_available": any(v.get("available", False) for v in product.get("variants", [])),
            "tags": ", ".join(product.get("tags", []))
        })
    return rows

Экспорт в CSV, Excel и Google Sheets

# Экспорт в CSV (используйте utf-8-sig, чтобы Excel корректно обрабатывал спецсимволы)
df.to_csv("shopify_products.csv", index=False, encoding="utf-8-sig")

# Экспорт в Excel (требует openpyxl)
df.to_excel("shopify_products.xlsx", index=False, engine="openpyxl")

print("Exported to shopify_products.csv and shopify_products.xlsx")

Для Google Sheets можно использовать библиотеку gspread и service account, но, честно говоря, для большинства задач проще и быстрее экспортировать в CSV, а затем загрузить файл в Google Drive.

Парсинг Shopify в продакшене: лимиты, ретраи и защита от блокировок

Базовый скрипт нормально работает на небольших магазинах. Но если вы парсите магазин с 5,000+ товарами или несколько магазинов подряд, начинаются проблемы.

Как Shopify ограничивает запросы и блокирует трафик

У публичных JSON-эндпоинтов Shopify нет официально опубликованных лимитов (в отличие от модели leaky bucket в Admin API), но на практике видно следующее:

  • Безопасная скорость: около 2 запросов в секунду на один магазин
  • Мягкий предел: примерно 40 запросов в минуту, после чего начинается throttling
  • HTTP 429: «Too Many Requests» — стандартный ответ на превышение лимита
  • HTTP 430: специфичный для Shopify код, означающий блокировку на уровне безопасности, а не просто rate limiting
  • HTTP 403 или редирект на CAPTCHA: у некоторых магазинов включена дополнительная защита Cloudflare

Запросы из облачных инфраструктур общего пользования (AWS Lambda, Google Cloud Run) особенно часто приводят к блокировкам, потому что с этих IP-диапазонов идёт высокий уровень злоупотреблений.

Как надёжно парсить Shopify

Вот путь от «работает на моём ноутбуке» до «готово для продакшена»:

УровеньТехникаНадёжность
Базовыйrequests.get() + ?page=Ломается на больших каталогах, может получить блокировку
Среднийrequests.Session() + ?limit=250 + time.sleep(1) + retry на 429Работает на большинстве магазинов
ПродвинутыйAsync httpx + ротация User-Agent + экспоненциальный backoffПодходит для продакшена, масштабируется до 10K+ товаров

Средний уровень (рекомендуется большинству пользователей):

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

def create_session():
    """Create a requests session with automatic retry logic."""
    session = requests.Session()
    retries = Retry(
        total=5,
        backoff_factor=1,  # sleep: 0.5s, 1s, 2s, 4s, 8s
        status_forcelist=[429, 430, 500, 502, 503, 504],
        respect_retry_after_header=True
    )
    session.mount("https://", HTTPAdapter(max_retries=retries))
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
    })
    return session

Конфигурация Retry автоматически обрабатывает ответы 429 с экспоненциальной задержкой. Параметр backoff_factor=1 означает последовательность пауз 0.5 с → 1 с → 2 с → 4 с → 8 с между повторными попытками. Повторное использование requests.Session() даёт ещё и pooling соединений, что снижает накладные расходы при серии запросов к одному домену.

Ротация User-Agent: если вы парсите несколько магазинов, чередуйте 3–5 реалистичных браузерных User-Agent. Это не про обман, а про то, чтобы не выглядеть как бот с одинаковыми заголовками в каждом запросе.

Полный рабочий Python-скрипт для парсинга Shopify с экспортом в CSV

Ниже — полный скрипт, который можно просто скопировать и запустить. В нём примерно 75 строк реального кода (плюс комментарии), и я тестировал его на Allbirds (1,420 товаров), ColourPop (2,000+ товаров) и Zoologist Perfumes (небольшой каталог).

import requests
import pandas as pd
import time
import random
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry


def create_session():
    """Create a session with retry logic for rate limits."""
    session = requests.Session()
    retries = Retry(
        total=5,
        backoff_factor=1,
        status_forcelist=[429, 430, 500, 502, 503, 504],
        respect_retry_after_header=True
    )
    session.mount("https://", HTTPAdapter(max_retries=retries))
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                      "AppleWebKit/537.36 (KHTML, like Gecko) "
                      "Chrome/125.0.0.0 Safari/537.36"
    })
    return session


def scrape_shopify(store_url, delay=1.0):
    """Scrape all products from a Shopify store via /products.json."""
    session = create_session()
    all_products = []
    page = 1
    base_url = f"{store_url.rstrip('/')}/products.json"

    while True:
        print(f"  Page {page}...", end=" ")
        resp = session.get(base_url, params={"limit": 250, "page": page}, timeout=30)
        resp.raise_for_status()
        products = resp.json().get("products", [])

        if not products:
            break

        all_products.extend(products)
        print(f"{len(products)} products (total: {len(all_products)})")
        page += 1
        time.sleep(delay + random.uniform(0, 0.5))

    return all_products


def flatten_to_variants(products):
    """Flatten nested product JSON into one row per variant."""
    rows = []
    for p in products:
        base = {
            "product_id": p["id"],
            "title": p["title"],
            "handle": p["handle"],
            "vendor": p.get("vendor", ""),
            "product_type": p.get("product_type", ""),
            "tags": ", ".join(p.get("tags", [])),
            "created_at": p.get("created_at", ""),
            "updated_at": p.get("updated_at", ""),
            "image_url": p["images"][0]["src"] if p.get("images") else "",
        }
        for v in p.get("variants", []):
            row = {**base}
            row["variant_id"] = v["id"]
            row["variant_title"] = v.get("title", "")
            row["sku"] = v.get("sku", "")
            row["price"] = v.get("price", "")
            row["compare_at_price"] = v.get("compare_at_price", "")
            row["available"] = v.get("available", "")
            rows.append(row)
    return rows


if __name__ == "__main__":
    STORE_URL = "https://allbirds.com"  # Change this to your target store
    OUTPUT_CSV = "shopify_products.csv"
    OUTPUT_EXCEL = "shopify_products.xlsx"

    print(f"Scraping {STORE_URL}...")
    products = scrape_shopify(STORE_URL)
    print(f"\nTotal products scraped: {len(products)}")

    print("Flattening to variant-level rows...")
    rows = flatten_to_variants(products)
    df = pd.DataFrame(rows)
    print(f"DataFrame: {df.shape[0]} rows x {df.shape[1]} columns")

    df.to_csv(OUTPUT_CSV, index=False, encoding="utf-8-sig")
    df.to_excel(OUTPUT_EXCEL, index=False, engine="openpyxl")
    print(f"\nExported to {OUTPUT_CSV} and {OUTPUT_EXCEL}")

Запустите его командой python scrape_shopify.py. Для Allbirds это занимает около 45 секунд и создаёт CSV примерно с 5,000+ строками (по одной на вариант). Вывод в терминале будет примерно таким:

Scraping https://allbirds.com...
  Page 1... 250 products (total: 250)
  Page 2... 250 products (total: 500)
  ...
  Page 6... 170 products (total: 1420)

Total products scraped: 1420
Flattening to variant-level rows...
DataFrame: 5680 rows x 14 columns

Exported to shopify_products.csv and shopify_products.xlsx

Пропустите Python: парсите Shopify в 2 клика с Thunderbit (no-code альтернатива)

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

Именно поэтому мы создали Thunderbit Official Website — AI web scraper в формате расширения Chrome. Никакого кода, никаких API-ключей, никакой настройки окружения.

Попробовать расширение Thunderbit для Chrome

Как Thunderbit парсит магазины на Shopify

В Thunderbit есть готовый Shopify Scraper template, уже настроенный под страницы товаров Shopify. Вы устанавливаете страницу загрузки расширения Thunderbit Chrome Extension, переходите в магазин на Shopify и нажимаете «Scrape». Шаблон автоматически извлекает названия товаров, описания, цены, детали вариантов, изображения и информацию о продавце.

Если шаблон не совпадает идеально с конкретным магазином (кастомная тема, необычная верстка), функция Thunderbit AI Suggest Fields анализирует страницу и автоматически предлагает названия колонок. Их можно подстроить: переименовать столбцы, добавить поля, написать инструкции вроде «извлекай только товары, у которых задан compare_at_price».

Несколько функций напрямую повторяют то, что делает Python-скрипт:

  • Парсинг подстраниц: автоматически открывает каждую страницу товара и обогащает таблицу полными описаниями, отзывами или деталями вариантов — по сути то же, что делает наш Python-скрипт через проход по страницам, но без кода.
  • Автоматическая пагинация: обрабатывает переход по страницам и бесконечную прокрутку без дополнительной настройки.
  • Плановый запуск: можно настроить повторяющиеся задачи (например, «каждый понедельник в 9:00») для постоянного мониторинга цен — без cron и без сервера.
  • Бесплатный экспорт в CSV, Excel, Google Sheets, Airtable или Notion на всех тарифах.

Python-скрипт vs Thunderbit: честное сравнение

ФакторPython-скриптThunderbit (no-code)
Время на настройку15–60 мин (окружение + код)~2 мин (установить расширение Chrome)
Нужен кодДа (Python)Нет
НастройкаБез ограниченийПоля, предложенные AI, + собственные промпты
ПагинацияНужно писать вручнуюАвтоматически
Форматы экспортаНужно реализовать самому (CSV/Excel)CSV, Excel, Google Sheets, Airtable, Notion (бесплатно)
Периодические запускиCron + хостингВстроенный планировщик
Работа с rate limitsНужно писать retries/backoffОбрабатывается автоматически
Лучше всего подходит дляРазработчиков, больших data pipelineБизнес-пользователей, быстрых выгрузок, регулярного мониторинга

Используйте Python, когда нужен полный контроль или вы встраиваете сбор данных в более крупный pipeline. Используйте Thunderbit, когда данные нужны быстро и вы не хотите поддерживать код. Более подробно о парсинге веб-сайтов для сравнения цен мы отдельно писали в другом руководстве.

python-vs-thunderbit-comparison.webp

Советы и лучшие практики при парсинге Shopify-магазинов

Они актуальны независимо от того, какой инструмент вы выберете:

  • Всегда используйте ?limit=250, чтобы сократить число запросов. При стандартных 30 товарах на страницу запросов будет в 8 раз больше при тех же данных.
  • Уважайте магазин: делайте задержку 1–2 секунды между запросами. Агрессивные частые запросы — плохая практика и повышают риск блокировки.
  • Сначала проверьте robots.txt: стандартный robots.txt Shopify не блокирует /products.json. Но некоторые магазины добавляют свои правила, поэтому перед массовым парсингом это стоит проверить.
  • Сохраняйте сырой JSON локально, а уже потом обрабатывайте его. Если логика парсинга изменится, не придётся собирать данные заново. Простого json.dump(all_products, open("raw_data.json", "w")) перед преобразованием достаточно, чтобы сэкономить много времени.
  • Удаляйте дубликаты по product.id: на границах страниц иногда могут попадаться повторяющиеся товары. Быстрый df.drop_duplicates(subset=["product_id", "variant_id"]) решает проблему.
  • Преобразуйте price в float перед вычислениями. Shopify возвращает цены строкой ("185.00"), а не числом.
  • Следите за изменениями эндпоинта: хотя /products.json стабилен уже много лет, теоретически Shopify может его ограничить. Если скрипт внезапно начал получать 404, сначала проверьте магазин вручную.

Если хотите узнать больше о создании надёжных скрейперов, посмотрите наше руководство по лучшим практикам web scraping tools.

Юридические и этические аспекты парсинга Shopify

Короткий раздел, но важный.

Эндпоинт /products.json отдаёт общедоступные данные о товарах — ту же информацию, которую видит любой посетитель магазина. В Terms of Service Shopify есть формулировки о запрете использовать «автоматизированные средства» для доступа к «Services», но это относится к самой платформе (админ-панель, checkout), а не к публичным данным витрины. По состоянию на апрель 2026 года не было подано ни одного иска, специфичного именно для парсинга Shopify.

Ключевые судебные прецеденты поддерживают сбор публичных данных: дело hiQ v. LinkedIn подтвердило, что парсинг общедоступной информации не нарушает CFAA, а Meta v. Bright Data (2024) постановило, что ограничения ToS действуют только тогда, когда пользователь вошёл в систему.

Лучшие практики:

  • Парсите только общедоступные данные о товарах
  • Не собирайте персональные данные и данные клиентов
  • Соблюдайте robots.txt и rate limits
  • Соблюдайте GDPR/CCPA, если обрабатываете персональные данные (данные каталога товаров не являются персональными)
  • Используйте понятный User-Agent
  • Парсить свой собственный магазин Shopify через Admin API — всегда нормально

Для более глубокого разбора см. наш материал о юридических аспектах web scraping.

Выводы и главное

Публичный эндпоинт Shopify /products.json делает извлечение e-commerce данных максимально простым. Рабочий процесс такой: добавить /products.json → получить данные на Python → пройти пагинацию через ?limit=250&page= → превратить JSON в таблицу с помощью pandas → экспортировать в CSV или Excel.

Что это руководство даёт сверх обычных статей:

  • Полный справочник по полям: вы заранее знаете, какие данные доступны (40+ полей на уровне товаров, вариантов и изображений), ещё до написания первой строки кода
  • Дополнительные эндпоинты: /collections.json и /meta.json дают аналитику по категориям и метаданные магазина, чего нет у большинства конкурирующих статей
  • Техники для продакшена: повторное использование сессии, экспоненциальный backoff, заголовки User-Agent и ?limit=250 для работы с реальными rate limits
  • Корректный экспорт в CSV/Excel: плоские данные на уровне вариантов через pandas, а не просто выгрузка сырого JSON
  • No-code альтернатива: Thunderbit для тех, кому важнее скорость, чем гибкость кода

Для разовых или регулярных выгрузок данных Shopify без кода попробуйте страницу загрузки Thunderbit Chrome Extension — шаблон Shopify Scraper сам справится со всем: от пагинации до экспорта. Если же вам нужны кастомные data pipeline или масштабный парсинг сразу по многим магазинам, Python-скрипт из этого руководства даст полный контроль.

Посмотрите наш Thunderbit YouTube Channel с видеоинструкциями или изучите наши материалы о парсинге товаров Amazon и извлечении данных с сайтов в Excel — там тоже много полезных приёмов.

Попробуйте Thunderbit для парсинга Shopify Get Started Free

Часто задаваемые вопросы

Можно ли парсить любой магазин Shopify через products.json?

У большинства магазинов Shopify этот эндпоинт открыт по умолчанию — в тестах валидный JSON возвращали около 71% сайтов. У некоторых магазинов с кастомной конфигурацией или дополнительными уровнями защиты (Cloudflare, headless-архитектура) может возвращаться 404 или блокироваться запрос. Быстрая проверка: откройте {store-url}/products.json в браузере. Если видите JSON, значит всё в порядке.

Законно ли парсить магазины Shopify?

Публичные данные о товарах (цены, названия, изображения, описания) обычно доступны, а судебные прецеденты вроде hiQ v. LinkedIn поддерживают сбор общедоступной информации. При этом всегда проверяйте Terms of Service конкретного магазина и местные законы. Не собирайте персональные данные и данные клиентов, а также соблюдайте rate limits.

Сколько товаров можно спарсить из магазина Shopify?

Жёсткого общего лимита нет. Пагинация через ?limit=250&page= позволяет получить весь каталог. Для очень крупных магазинов (25,000+ товаров) используйте повторное использование сессии и задержки, чтобы не упереться в rate limits. Эндпоинт /meta.json заранее покажет точное количество товаров, чтобы вы понимали, сколько страниц ожидать.

В чём разница между products.json и Shopify Admin API?

/products.json — это публичный эндпоинт: без авторизации, только чтение, доступен всем. Admin API требует токены доступа владельца магазина и даёт заказы, количество остатков, данные о клиентах и возможность записи. Если нужны данные о продажах или реальные остатки, нужен доступ к Admin API (то есть вы должны быть владельцем магазина или иметь его разрешение).

Можно ли парсить Shopify без Python?

Абсолютно. Инструменты вроде Thunderbit Official Website позволяют собирать данные с Shopify через расширение Chrome без кода. Пагинация обрабатывается автоматически, а экспорт идёт сразу в CSV, Excel, Google Sheets, Airtable или Notion. Для разработчиков, предпочитающих другие языки, тот же /products.json работает с JavaScript, Ruby, Go — любым языком, который умеет делать HTTP-запросы и парсить JSON.

Узнать больше

Ke
Ke
Технический директор в Thunderbit | Senior Data Scientist и эксперт по ML Имея почти десятилетний опыт в машинном обучении и data science, Кэ Шэнь — выпускник Колумбийского университета и бывший Senior Data Scientist в Walmart Labs. Обладая глубокой, признанной коллегами экспертизой в Python, R, Java и статистике, он делится проверенными на практике наблюдениями о том, как переводить сложные AI-алгоритмы из теории в production-grade архитектуру.

Попробуй Thunderbit

Собирай лиды и другие данные всего в 2 клика. На базе AI.

Получить Thunderbit Это бесплатно
Извлекай данные с помощью AI
Легко передавай данные в Google Sheets, Airtable или Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week