Скрапинг Shopify products.json: конечная точка, которую открывает каждый магазин

Забудьте про парсинг HTML. Каждый магазин на Shopify предоставляет вам чистый JSON на /products.json — полный каталог, цены, варианты, наличие. Вот ограничения пагинации, ускоряющие трюки и как превратить это в мониторинг конкурентов.

Любой, кто занимался скрапингом электронной коммерции, знает эту боль: хрупкие CSS-селекторы, вложенные div-обертки, макеты, которые меняются и ломают всё за ночь. Shopify предлагает вам выход. Почти каждый магазин на Shopify открывает публичную конечную точку /products.json, которая возвращает весь каталог в виде чистого, структурированного JSON — заголовки, идентификаторы, поставщики, теги, варианты, цены, флаги наличия и изображения. Никакого парсинга HTML, никакого безголового браузера. Это руководство охватывает, как работает конечная точка, её реальные ограничения пагинации, трюк, который значительно ускоряет сканирование больших магазинов, и как превратить всё это в мониторинг цен и наличия у конкурентов.

Конечная точка в каждом магазине Shopify

Добавьте /products.json к корневому домену любого магазина Shopify, и вы получите JSON-список продуктов. Это те же данные, которые использует витрина, открытые по дизайну для Ajax API. Каждый продукт имеет стабильный числовой id, handle, vendor, product_type, tags, массив variants (каждый с собственной ценой, SKU и логическим available), и изображения. Это всё, что вы обычно скрапите с продуктовой страницы, доставляется в одном запросе.

import requests

url = "https://store.example.com/products.json"
r = requests.get(url, params={"limit": 250, "page": 1}, timeout=15)
products = r.json()["products"]

print(len(products), products[0]["title"])
for v in products[0]["variants"]:
    print(v["sku"], v["price"], v["available"])

Два предостережения сразу. Shopify ограничивает публичную конечную точку до 250 продуктов на страницу — это ограничение, которое вы не можете превысить, независимо от того, что вы передаете, поэтому игнорируйте советы установить limit=1000000 и захватить всё в одном вызове. И меньшинство магазинов отключает конечную точку (иногда пользовательские сборки её отключают), поэтому проверьте на валидный ответ, прежде чем строить вокруг неё конвейер.

Пагинация до конца

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

def all_products(base):
    page, out = 1, []
    while True:
        r = requests.get(f"{base}/products.json",
                         params={"limit": 250, "page": page}, timeout=15)
        batch = r.json()["products"]
        if not batch:
            break
        out.extend(batch)
        page += 1
    return out
Диаграмма статистики, показывающая ограничения Shopify products.json: ограничение 250 продуктов на страницу, 25-кратное ускорение пагинации с бинарным поиском, 833 страницы в магазине с 25000 продуктов
Конечная точка ограничена 250 продуктами на страницу — скорость достигается за счёт быстрого нахождения последней страницы, а не за счёт больших запросов.

Трюк 25x: сначала найдите последнюю страницу

Последовательная пагинация медленная в больших магазинах, потому что вы не можете параллелизировать — вы не знаете, когда остановиться, поэтому каждая страница ждёт предыдущую. Решение — бинарный поиск: исследуйте номера страниц, чтобы найти последнюю непустую страницу, затем отправьте все запросы страниц одновременно. В публичном тесте против магазина с 25,000 продуктов на 833 страницах это сократило сканирование с примерно 120 секунд до около 12 на первом запуске и около 5, когда номер последней страницы был закэширован — 25-кратное ускорение. Направьте запросы через вращающиеся IP, чтобы всплеск одновременных запросов не вызвал ограничение.

PROXY = "http://USER:PASS@gate.quantumproxies.io:8000"
proxies = {"http": PROXY, "https": PROXY}

def last_page(base, hi=1000):
    lo, last = 1, 1
    while lo <= hi:
        mid = (lo + hi) // 2
        r = requests.get(f"{base}/products.json",
                         params={"limit": 250, "page": mid},
                         proxies=proxies, timeout=15)
        if r.json()["products"]:
            last, lo = mid, mid + 1   # go higher
        else:
            hi = mid - 1              # go lower
    return last
# then request pages 1..last_page concurrently

Как сказал Роб Пайк, сложные алгоритмы медленные, когда n мал — для магазина с 200 продуктами пропустите бинарный поиск и просто используйте цикл. Он окупается на каталогах в тысячи, где последовательная пагинация затягивает.

Сузьте выборку: коллекции и отдельные продукты

Вам не всегда нужен весь каталог. Shopify предоставляет тот же JSON на уровне коллекции: /collections/&lt;handle&gt;/products.json возвращает только продукты в этой коллекции, с той же пагинацией. Это эффективный путь, когда вы отслеживаете только одну категорию — кроссовки, ароматы, один бренд — а не весь магазин. А чтобы изучить один продукт, добавьте .json к его URL: /products/&lt;handle&gt;.json даст полную запись этого продукта, включая каждый вариант и его флаг наличия, что удобно для плотного отслеживания пополнения конкретного SKU без повторного сканирования каталога.

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

Превратите это в мониторинг конкурентов

Настоящая ценность — не одноразовый дамп каталога, а разница со временем. Делайте снимки products.json конкурента по расписанию, ключ по id варианта, и сравнивайте запуски, чтобы поймать изменения цен, новые продукты и пополнения в момент их появления. Поскольку available и price находятся на каждом варианте, вы получаете сигналы о наличии и ценах, не касаясь страницы продукта.

def snapshot(base):
    rows = {}
    for p in all_products(base):
        for v in p["variants"]:
            rows[v["id"]] = {
                "product": p["title"],
                "sku": v["sku"],
                "price": v["price"],
                "available": v["available"],
            }
    return rows

# diff today's snapshot against yesterday's to flag price + stock moves
def changes(old, new):
    for vid, cur in new.items():
        prev = old.get(vid)
        if prev and (prev["price"] != cur["price"] or prev["available"] != cur["available"]):
            yield cur["sku"], prev, cur

Это основа мониторинга цен конкурентов и исследования дропшиппинга — оба опираются на один и тот же шаблон снимков и различий по многим магазинам одновременно.

Получите быстрые датацентровые прокси для скрапинга Shopify

Диаграмма потока конвейера Shopify products.json: конечная точка к шлюзу вращающихся прокси к парсингу JSON варианта к различию снимков для мониторинга
Делайте снимки по расписанию, различайте варианты, и у вас будут живые оповещения о ценах и пополнениях по всем магазинам, которые вы отслеживаете.

Какие прокси вам действительно нужны

Конечная точка products.json — это публичный JSON, а не защищённый процесс оформления заказа, поэтому она прощает — но скрапьте сотни магазинов или атакуйте один по расписанию, и вы столкнётесь с ограничениями по скорости для каждого IP. Экономичный ответ — быстрые датацентровые прокси с ротацией: дешёвые, быстрые и достаточно, чтобы распределить запросы по IP, чтобы ни один из них не был ограничен. Зарезервируйте резидентные IP для магазинов, которые блокируют диапазоны датацентров. Если магазин отключил products.json и скрывает свой каталог за рендерингом страниц или защитой от ботов, Scraper API, который рендерит и вращает за вас, будет более чистым вариантом. Наш гайд по тому, когда выигрывают датацентровые прокси охватывает это решение.

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

Как получить все продукты из магазина Shopify в формате JSON?

Запросите /products.json на домене магазина с ?limit=250&page=N и увеличивайте page, пока страница не вернёт пустой массив продуктов. Каждый ответ содержит до 250 продуктов с их вариантами, ценами, SKU и флагами наличия. Для больших каталогов используйте бинарный поиск последней страницы и загружайте страницы одновременно.

Какое ограничение на Shopify products.json?

Публичная конечная точка ограничена 250 продуктами на страницу — это максимальное значение, которое принимает limit. Передача большего числа не вернёт больше; вам всё равно придётся проходить через каталог. Это жёсткое ограничение Shopify, поэтому планируйте пагинацию, а не пытайтесь получить всё в одном запросе.

Является ли скрапинг Shopify products.json законным?

Конечная точка предоставляет общедоступные данные о продуктах без входа в систему, и суды США в целом поддерживали скрапинг публичных данных. Тем не менее, уважайте условия использования магазина, избегайте личных данных и не перегружайте сервер. Это общая информация, а не юридическая консультация — проверьте специфику для вашего случая использования и юрисдикции.

Почему products.json возвращает 404 или пустой ответ?

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

Конечная точка products.json превращает скрапинг Shopify из задачи по управлению селекторами в чистую загрузку JSON: полный каталог, цены и наличие в одном URL, 250 на страницу, быстро для сканирования с бинарным поиском и тривиально для различия в мониторинге конкурентов. Откройте один раз, опрашивайте коллекции и продукты, которые имеют значение, распределяйте запросы по вращающимся датацентровым IP, и вы сможете отслеживать сотни магазинов по расписанию без единого заблокированного запуска — без парсера HTML, без безголового браузера, без хрупких селекторов, которые нужно нянчить.

Начните скрапинг Shopify с QuantumProxies