Endpoint Shopify /products.json to jedna z najbardziej znanych „tajemnic” w świecie danych e-commerce. Wystarczy dopisać go do adresu dowolnego sklepu Shopify, a w odpowiedzi dostaniesz uporządkowany JSON — bez kluczy API, bez autoryzacji i bez przekopywania się przez zagnieżdżony HTML.
Pracuję w zespole , więc na co dzień sporo myślę o tym, jak ludzie pozyskują dane z internetu. A scrapowanie Shopify wraca jak bumerang — zespoły sprzedaży śledzą ceny konkurencji, osoby z e-commerce porównują katalogi produktów, a działy zakupów wyszukują nowych dostawców. Przy na Shopify i udziale platformy wynoszącym około , ilość danych produktowych możliwych do zebrana jest ogromna.
Ten przewodnik pokazuje cały proces: co zwraca endpoint, jak przechodzić przez tysiące produktów strona po stronie, jak nie wpaść w limity i blokady, oraz jak spłaszczyć zagnieżdżony JSON Shopify do czystego pliku CSV lub Excela za pomocą pandas. Pokażę też endpointy, o których mało kto wspomina (/collections.json, /meta.json), a na końcu dorzucę też opcję no-code dla osób, które wolą całkiem pominąć Pythona.
Czym jest endpoint Shopify /products.json i dlaczego tak ułatwia scraping?
Każdy sklep Shopify ma publiczny endpoint pod adresem {store-url}/products.json, który zwraca uporządkowane dane o produktach. Bez kluczy API. Bez OAuth. Bez żadnego logowania. W praktyce wystarczy dopisać /products.json do adresu sklepu, aby dostać JSON z całym katalogiem produktów.
Sprawdź to sam: otwórz w przeglądarce albo . Zobaczysz czytelny, uporządkowany JSON z tytułami produktów, cenami, wariantami, zdjęciami, tagami — wszystkim, czego potrzeba.
Porównaj to z alternatywą: analizą HTML motywów Shopify, które są mocno zagnieżdżone, różnią się między sklepami i zmieniają się za każdym razem, gdy właściciel sklepu podmieni motyw. Oto z czym musiałbyś się mierzyć:
Podejście oparte na HTML (bolesne):
1<div class="product-card__info">
2 <h3 class="product-card__title">
3 <a href="/products/classic-blue-jeans">Classic Blue Jeans</a>
4 </h3>
5 <span class="price price--on-sale" data-product-price>$149.00</span>
6</div>
Podejście oparte na JSON (czyste):
1{
2 "title": "Classic Blue Jeans",
3 "handle": "classic-blue-jeans",
4 "vendor": "Hiut Denim",
5 "variants": [{"price": "149.00", "sku": "HD-BLU-32", "available": true}]
6}
JSON wygrywa pod względem spójności, niezawodności i łatwości parsowania. Endpoint obsługuje też dwa ważne parametry zapytania — ?limit= (do 250 produktów na stronę, domyślnie 30) oraz ?page= do paginacji — i właśnie z nich będziemy intensywnie korzystać w kodzie poniżej.
Ważne rozróżnienie: to jest publiczny endpoint sklepu, a nie . Admin API wymaga tokenów właściciela sklepu i daje dostęp do danych o zamówieniach, stanach magazynowych i klientach. Publiczny endpoint /products.json zwraca tylko dane produktowe w trybie odczytu, dostępne dla każdego. W dalszej części dokładnie wyjaśnię tę różnicę, bo w internecie panuje wokół tego spory chaos.
Jeden haczyk: nie każdy sklep Shopify udostępnia ten endpoint. Z moich testów wynika, że około 71% sklepów zwraca poprawny JSON (allbirds.com, gymshark.com, colourpop.com, kyliecosmetics.com działają), ale część niestandardowych konfiguracji zwraca 404 (hiutdenim.co.uk, bombas.com). Szybki test jest prosty: wejdź na {store-url}/products.json i sprawdź wynik.
Dlaczego scrapować Shopify w Pythonie? Najważniejsze zastosowania biznesowe
Po co to wszystko? Chodzi o zwrot z inwestycji. korzysta dziś z automatycznego monitorowania cen do analizy konkurencji, podczas gdy w 2020 roku było to tylko 34%. Badania pokazują też, że . Te dane naprawdę mają wartość.
Oto najczęstsze zastosowania, z którymi się spotykam:
| Przypadek użycia | Kto zyskuje | Co otrzymujesz |
|---|---|---|
| Monitoring cen konkurencji | Zespoły e-commerce | Śledzenie zmian cen, promocji i cen porównawczych w katalogach konkurencji |
| Badanie produktów i sourcing | Zakupy / merchandising | Porównanie cech produktów, wariantów, materiałów i dostępności |
| Generowanie leadów | Zespoły sprzedaży | Pozyskiwanie nazw dostawców, danych marek i informacji kontaktowych z katalogów sklepów |
| Analiza rynku i kategorii | Zespoły marketingowe | Zrozumienie miksu produktów, tagów, struktury kolekcji i pozycjonowania |
| Śledzenie stanów i dostępności | Zespoły supply chain | Monitorowanie statusu dostępności wariantów (available: true/false) w czasie |
| Wykrywanie nowych produktów | Zespoły produktowe | Analiza znaczników created_at, aby wyłapywać nowe premiery konkurencji |
Python jest naturalnym wyborem do tego typu pracy. używa Pythona jako głównego języka, a ekosystem — requests do HTTP, pandas do obróbki danych, httpx do asynchroniczności — pozwala przejść od „mam URL” do „mam arkusz kalkulacyjny” w mniej niż 80 liniach kodu.
Pełna dokumentacja pól products.json: wyjaśnienie każdego pola
Większość podobnych poradników pokazuje tylko title, id i handle, a potem przechodzi dalej. Tymczasem odpowiedź JSON Shopify zawiera ponad 40 pól obejmujących produkty, warianty, obrazy i opcje. Wiedza o tym, co jest dostępne, zanim napiszesz scraper, oszczędza późniejszego ponownego pobierania danych.
Ten zestaw przygotowałem na podstawie rzeczywistych odpowiedzi /products.json pobranych 16 kwietnia 2026 r. Struktura jest spójna we wszystkich sklepach, które udostępniają ten endpoint.
Pola na poziomie produktu
| Pole | Typ danych | Przykład | Zastosowanie biznesowe |
|---|---|---|---|
id | Integer | 123456789 | Unikalny identyfikator produktu do deduplikacji |
title | String | "Classic Blue Jeans" | Nazwa produktu do katalogów i porównań |
handle | String | "classic-blue-jeans" | Slug URL — buduj linki do produktu jako {store}/products/{handle} |
body_html | String (HTML) lub null | Our best-selling... | Opis produktu do analizy treści i badań SEO |
vendor | String | "Hiut Denim" | Nazwa marki/dostawcy do generowania leadów lub sourcingu |
product_type | String | "Jeans" | Kategoryzacja do analizy rynku |
created_at | ISO DateTime | "2024-01-15T10:30:00-05:00" | Śledzenie momentu dodania produktu (wykrywanie nowości) |
updated_at | ISO DateTime | "2025-03-01T08:00:00-05:00" | Wykrywanie ostatnich zmian w katalogu |
published_at | ISO DateTime | "2024-01-16T00:00:00-05:00" | Informacja, kiedy produkt pojawił się w sklepie |
tags | Array of Strings | ["organic", "women", "straight-leg"] | Analiza słów kluczowych/tagów pod SEO, klasyfikację i trendy |
variants | Array of Objects | (patrz pola wariantów poniżej) | Cena, SKU i dostępność każdego wariantu |
images | Array of Objects | (patrz pola obrazów poniżej) | Adresy zdjęć produktów do katalogów i analizy wizualnej |
options | Array of Objects | [{"name": "Size", "values": ["S","M","L"]}] | Zrozumienie konfiguracji produktu (rozmiar, kolor, materiał) |
Pola na poziomie wariantu (zagnieżdżone w produkcie)
| Pole | Typ danych | Przykład | Zastosowanie |
|---|---|---|---|
id | Integer | 987654321 | Unikalny identyfikator wariantu |
title | String | "32 / Blue" | Nazwa wyświetlana wariantu |
sku | String | "HD-BLU-32" | Dopasowanie SKU do systemów magazynowych |
price | String | "185.00" | Monitorowanie cen (uwaga: to string, do obliczeń trzeba rzutować na float) |
compare_at_price | String lub null | "200.00" | Cena wyjściowa — kluczowa do śledzenia rabatów |
available | Boolean | true | Dostępność towaru (jedyny publicznie widoczny wskaźnik stanu) |
weight | Float | 1.2 | Analiza wysyłki i logistyki |
option1, option2, option3 | String | "32", "Blue", null | Poszczególne wartości opcji |
created_at, updated_at | ISO DateTime | — | Śledzenie zmian na poziomie wariantu |
Pola na poziomie obrazu
| Pole | Typ danych | Przykład | Zastosowanie |
|---|---|---|---|
id | Integer | 111222333 | Unikalny identyfikator obrazu |
src | String (URL) | "https://cdn.shopify.com/..." | Bezpośredni link do pobrania obrazu |
alt | String lub null | "Front view of jeans" | Tekst alternatywny do analizy dostępności |
position | Integer | 1 | Kolejność obrazów |
width, height | Integer | 2048, 2048 | Wymiary obrazu |
Czego NIE ma w publicznym endpointcie
Ważna pułapka: inventory_quantity NIE jest dostępne w publicznych odpowiedziach /products.json. To pole zostało usunięte z publicznych endpointów JSON w grudniu 2017 roku ze względów bezpieczeństwa. Jedynym publicznym wskaźnikiem stanu magazynowego jest boolean available przy każdym wariancie (true albo false). Aby uzyskać rzeczywiste ilości magazynowe, potrzebujesz uwierzytelnionego Admin API i danych właściciela sklepu.
Zanim napiszesz scraper, przejrzyj tę tabelę i zdecyduj, które pola są Ci potrzebne. Jeśli monitorujesz ceny, potrzebujesz variants[].price, variants[].compare_at_price i variants[].available. Jeśli generujesz leady, skup się na vendor, product_type i tags. Odfiltrowanie zbędnych danych od razu sprawi, że CSV będzie dużo czytelniejszy.
Poza products.json: kolekcje, meta i inne endpointy Shopify
Żaden z konkurencyjnych poradników nie wspomina o tych endpointach. A są one bardzo ważne w poważnej analizie konkurencji.
/collections.json — wszystkie kategorie sklepu
Zwraca wszystkie kolekcje (kategorie) w sklepie wraz z tytułami, handle’ami, opisami i liczbą produktów. Sprawdziłem to na zoologistperfumes.com, allbirds.com i gymshark.com — wszystkie zwróciły poprawny JSON.
1{
2 "collections": [
3 {
4 "id": 308387348539,
5 "title": "Attars",
6 "handle": "attars",
7 "published_at": "2026-03-29T12:20:32-04:00",
8 "products_count": 1,
9 "image": { "src": "https://cdn.shopify.com/..." }
10 }
11 ]
12}
Chcesz zrozumieć, jak konkurent porządkuje swój katalog? To właśnie ten endpoint.
/collections/{handle}/products.json — produkty w konkretnej kategorii
Zwraca produkty przefiltrowane do wybranej kolekcji. Struktura JSON jest taka sama jak w /products.json, ale ograniczona do jednej kategorii. To świetne rozwiązanie do scrapingu na poziomie kategorii — na przykład gdy chcesz śledzić tylko kolekcję „Sale” albo „New Arrivals”.
/meta.json — metadane sklepu
Zwraca nazwę sklepu, opis, walutę, kraj i — co najważniejsze — published_products_count. Dzięki temu możesz od razu policzyć, ile stron paginacji będzie potrzebnych: ceil(published_products_count / 250). Koniec z bezsensownym zwiększaniem numeru strony aż do pustej odpowiedzi.
Którego endpointu użyć?
| Czego potrzebujesz | Endpoint | Wymagana autoryzacja? |
|---|---|---|---|
| Wszystkie produkty (publiczne) | /products.json | Nie |
| Produkty z konkretnej kategorii | /collections/{handle}/products.json | Nie |
| Metadane sklepu + liczba produktów | /meta.json | Nie |
| Wszystkie kolekcje (kategorie) | /collections.json | Nie |
| Dane o zamówieniach/sprzedaży (tylko własny sklep) | Admin API /orders.json | Tak (klucz API) |
| Ilości magazynowe (tylko własny sklep) | Admin API /inventory_levels.json | Tak |
Często powracające pytanie na forach — „Czy mogę sprawdzić, ile sztuk sprzedał konkurent?” — ma krótką odpowiedź: nie. Nie z publicznych endpointów. Dane o sprzedaży i stanach magazynowych wymagają uwierzytelnionego Admin API, czyli dostępu właściciela sklepu. Publiczne endpointy dają tylko dane katalogowe.

Jak scrapować Shopify w Pythonie: konfiguracja krok po kroku
- Poziom trudności: Początkujący
- Czas potrzebny: ok. 15 minut (konfiguracja + pierwszy scraping)
- Czego potrzebujesz: Python 3.11+,
pip, terminal oraz adres sklepu Shopify do pobrania
Krok 1: Zainstaluj Pythona i wymagane biblioteki
Upewnij się, że masz zainstalowanego Pythona 3.11 lub nowszego (pandas 3.0.x tego wymaga). Następnie zainstaluj dwie potrzebne biblioteki:
1pip install requests pandas
Do eksportu do Excela przyda się również:
1pip install openpyxl
Na początku skryptu dodaj te importy:
1import requests
2import pandas as pd
3import time
4import random
5import json
Po uruchomieniu skryptu nie powinieneś widzieć błędów importu. Jeśli pandas zgłosi błąd wersji, zaktualizuj Pythona do 3.12.
Krok 2: Pobieranie danych o produktach z /products.json
Oto podstawowa funkcja, która przyjmuje adres sklepu, pobiera dane z endpointu i zwraca sparsowany JSON:
1def fetch_products_page(store_url, page=1, limit=250):
2 """Fetch a single page of products from a Shopify store."""
3 url = f"{store_url.rstrip('/')}/products.json"
4 params = {"limit": limit, "page": page}
5 headers = {
6 "User-Agent": "Mozilla/5.0 (compatible; ProductResearch/1.0)"
7 }
8 response = requests.get(url, params=params, headers=headers, timeout=30)
9 response.raise_for_status()
10 return response.json().get("products", [])
Najważniejsze szczegóły:
limit=250to maksymalna wartość dozwolona przez Shopify na stronę. Domyślnie jest 30, więc ustawienie tego parametru pozwala ograniczyć liczbę zapytań nawet 8-krotnie.- Nagłówek
User-Agent: zawsze ustawiaj realistyczny. Żądania bez User-Agent częściej uruchamiają zabezpieczenia antybotowe Shopify. timeout=30: nie pozwól, by pojedyncze żądanie zawiesiło się na wieczność.
Przetestuj to na znanym sklepie:
1products = fetch_products_page("https://allbirds.com")
2print(f"Fetched {len(products)} products")
3print(f"First product: {products[0]['title']}")
Powinieneś zobaczyć coś w rodzaju: Fetched 250 products oraz tytuł pierwszego produktu.
Krok 3: Obsługa paginacji, aby pobrać wszystkie produkty
Jedno żądanie zwraca maksymalnie 250 produktów. Większość sklepów ma ich więcej (Allbirds ma ponad 1 420). Trzeba przechodzić po stronach, aż pojawi się pusta odpowiedź.
1def scrape_all_products(store_url, delay=1.0):
2 """Scrape all products from a Shopify store, handling pagination."""
3 all_products = []
4 page = 1
5 while True:
6 print(f"Fetching page {page}...")
7 products = fetch_products_page(store_url, page=page, limit=250)
8 if not products:
9 print(f"No more products. Total: {len(all_products)}")
10 break
11 all_products.extend(products)
12 print(f" Got {len(products)} products (total so far: {len(all_products)})")
13 page += 1
14 # Zachowaj umiar: odczekaj między żądaniami
15 time.sleep(delay + random.uniform(0, 0.5))
16 return all_products
Gdy products zwróci pustą listę, oznacza to, że dotarłeś do końca.
time.sleep() z losowym jitterem pomaga utrzymać się poniżej nieformalnego limitu Shopify (~2 żądania na sekundę).
Wskazówka: jeśli najpierw pobierzesz /meta.json, już znasz całkowitą liczbę produktów i możesz obliczyć dokładnie, ile stron potrzebujesz: pages = ceil(product_count / 250). Dzięki temu unikniesz „jednego dodatkowego pustego żądania” na końcu.
Krok 4: Parsowanie i wybór potrzebnych pól
Skoro masz już wszystkie produkty jako listę słowników w Pythonie, wyciągnij tylko te pola, które naprawdę Cię interesują. Poniżej przykład dla monitoringu cen:
1def extract_product_data(products):
2 """Extract key fields from products, flattening variants."""
3 rows = []
4 for product in products:
5 for variant in product.get("variants", []):
6 rows.append({
7 "product_id": product["id"],
8 "title": product["title"],
9 "handle": product["handle"],
10 "vendor": product.get("vendor", ""),
11 "product_type": product.get("product_type", ""),
12 "tags": ", ".join(product.get("tags", [])),
13 "created_at": product.get("created_at", ""),
14 "variant_id": variant["id"],
15 "variant_title": variant.get("title", ""),
16 "sku": variant.get("sku", ""),
17 "price": variant.get("price", ""),
18 "compare_at_price": variant.get("compare_at_price", ""),
19 "available": variant.get("available", ""),
20 "image_url": product["images"][0]["src"] if product.get("images") else ""
21 })
22 return rows
To tworzy jeden wiersz na wariant — czyli format najbardziej przydatny do porównywania cen, bo pojedynczy produkt, taki jak „Classic Blue Jeans”, może mieć 12 wariantów (6 rozmiarów × 2 kolory), każdy z własną ceną i statusem dostępności.
Jak eksportować dane ze Shopify do CSV i Excela za pomocą pandas
W większości poradników o scrapingu Shopify kończy się na zapisaniu surowego JSON-a do pliku. Dla programisty — wystarczy. Dla analityka e-commerce, który potrzebuje arkusza na piątek, to za mało.
Problem polega na tym, że JSON Shopify jest zagnieżdżony. Jeden produkt może zawierać kilkanaście wariantów, a każdy ma własną cenę, SKU i dostępność. Spłaszczenie tego do wierszy i kolumn wymaga pracy z pandas.
Jak spłaszczyć zagnieżdżony JSON do czystej tabeli
Są dwa podejścia, zależnie od potrzeb:
Opcja A: Jeden wiersz na wariant (najlepsza do monitorowania cen i stanów magazynowych)
1# Using the extract_product_data function from Step 4
2products = scrape_all_products("https://allbirds.com")
3rows = extract_product_data(products)
4df = pd.DataFrame(rows)
5print(f"DataFrame shape: {df.shape}")
6print(df.head())
To daje płaską tabelę, w której każdy wiersz to unikalna kombinacja produktu i wariantu. Sklep z 500 produktami i średnio 4 wariantami na produkt da DataFrame liczący około 2 000 wierszy.
Opcja B: Jeden wiersz na podsumowanie produktu (najlepsza do przeglądu katalogu)
1def summarize_products(products):
2 """One row per product with min/max price across variants."""
3 rows = []
4 for product in products:
5 prices = [float(v["price"]) for v in product.get("variants", []) if v.get("price")]
6 rows.append({
7 "product_id": product["id"],
8 "title": product["title"],
9 "vendor": product.get("vendor", ""),
10 "product_type": product.get("product_type", ""),
11 "variant_count": len(product.get("variants", [])),
12 "min_price": min(prices) if prices else None,
13 "max_price": max(prices) if prices else None,
14 "any_available": any(v.get("available", False) for v in product.get("variants", [])),
15 "tags": ", ".join(product.get("tags", []))
16 })
17 return rows
Eksport do CSV, Excela i Google Sheets
1# CSV export (use utf-8-sig so Excel handles special characters)
2df.to_csv("shopify_products.csv", index=False, encoding="utf-8-sig")
3# Excel export (requires openpyxl)
4df.to_excel("shopify_products.xlsx", index=False, engine="openpyxl")
5print("Exported to shopify_products.csv and shopify_products.xlsx")
Do Google Sheets możesz użyć biblioteki gspread z kontem serwisowym, ale szczerze mówiąc — w większości przypadków szybciej i prościej jest wyeksportować CSV i wrzucić plik do Google Drive.
Scraping produkcyjny w Pythonie: limity, retry i ochrona przed blokadą
Podstawowy skrypt dobrze radzi sobie z małymi sklepami. Ale scrapowanie sklepu z ponad 5 000 produktów albo wielu sklepów po kolei? Wtedy zaczynają się schody.
Jak działają limity i blokady Shopify
Publiczne endpointy JSON Shopify nie mają formalnie udokumentowanych limitów jak Admin API (który korzysta z modelu leaky bucket), ale testy praktyczne pokazują:
- Bezpieczne tempo: około 2 żądania na sekundę na sklep
- Miękki próg: około 40 żądań na minutę, zanim zacznie działać throttling
- HTTP 429: „Too Many Requests” — standardowa odpowiedź limitu
- HTTP 430: kod specyficzny dla Shopify, oznaczający blokadę bezpieczeństwa, a nie tylko limitowanie
- HTTP 403 lub przekierowanie do CAPTCHA: w niektórych sklepach z dodatkową ochroną Cloudflare
Żądania z publicznych chmur (AWS Lambda, Google Cloud Run) częściej wywołują blokady, bo zakresy IP z tych usług mają wyższy poziom nadużyć.
Jak scrapować Shopify niezawodnie
Oto droga od „działa na moim laptopie” do „działa produkcyjnie”:
| Poziom | Technika | Niezawodność |
|---|---|---|
| Podstawowy | requests.get() + ?page= | Psuje się przy dużych katalogach, może zostać zablokowany |
| Średni | requests.Session() + ?limit=250 + time.sleep(1) + retry dla 429 | Działa w większości sklepów |
| Zaawansowany | Asynchroniczny httpx + rotacja User-Agent + exponential backoff | Gotowe do produkcji, skaluje się do 10 tys.+ produktów |
Poziom średni (polecany większości użytkowników):
1import requests
2from requests.adapters import HTTPAdapter
3from urllib3.util.retry import Retry
4def create_session():
5 """Create a requests session with automatic retry logic."""
6 session = requests.Session()
7 retries = Retry(
8 total=5,
9 backoff_factor=1, # sleep: 0.5s, 1s, 2s, 4s, 8s
10 status_forcelist=[429, 430, 500, 502, 503, 504],
11 respect_retry_after_header=True
12 )
13 session.mount("https://", HTTPAdapter(max_retries=retries))
14 session.headers.update({
15 "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"
16 })
17 return session
Konfiguracja Retry automatycznie obsługuje odpowiedzi 429 dzięki exponential backoff. backoff_factor=1 oznacza, że przerwy między próbami będą wynosić 0,5 s → 1 s → 2 s → 4 s → 8 s. Ponowne użycie sesji (requests.Session()) daje też pooling połączeń, co zmniejsza narzut przy wielu żądaniach do tej samej domeny.
Rotacja User-Agent: jeśli scrapujesz wiele sklepów, przełączaj się między 3–5 realistycznymi stringami User-Agent przeglądarki. Nie chodzi o „oszukiwanie”, tylko o to, by nie wyglądać jak bot wysyłający identyczne nagłówki przy każdym zapytaniu.
Gotowy skrypt w Pythonie do scrapowania Shopify z eksportem CSV
Poniżej znajdziesz kompletny, gotowy do wklejenia skrypt, który łączy wszystko powyżej. Ma około 75 linii realnego kodu (plus komentarze) i testowałem go na Allbirds (1 420 produktów), ColourPop (ponad 2 000 produktów) oraz Zoologist Perfumes (mały katalog).
1import requests
2import pandas as pd
3import time
4import random
5from requests.adapters import HTTPAdapter
6from urllib3.util.retry import Retry
7def create_session():
8 """Create a session with retry logic for rate limits."""
9 session = requests.Session()
10 retries = Retry(
11 total=5,
12 backoff_factor=1,
13 status_forcelist=[429, 430, 500, 502, 503, 504],
14 respect_retry_after_header=True
15 )
16 session.mount("https://", HTTPAdapter(max_retries=retries))
17 session.headers.update({
18 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
19 "AppleWebKit/537.36 (KHTML, like Gecko) "
20 "Chrome/125.0.0.0 Safari/537.36"
21 })
22 return session
23def scrape_shopify(store_url, delay=1.0):
24 """Scrape all products from a Shopify store via /products.json."""
25 session = create_session()
26 all_products = []
27 page = 1
28 base_url = f"{store_url.rstrip('/')}/products.json"
29 while True:
30 print(f" Page {page}...", end=" ")
31 resp = session.get(base_url, params={"limit": 250, "page": page}, timeout=30)
32 resp.raise_for_status()
33 products = resp.json().get("products", [])
34 if not products:
35 break
36 all_products.extend(products)
37 print(f"{len(products)} products (total: {len(all_products)})")
38 page += 1
39 time.sleep(delay + random.uniform(0, 0.5))
40 return all_products
41def flatten_to_variants(products):
42 """Flatten nested product JSON into one row per variant."""
43 rows = []
44 for p in products:
45 base = {
46 "product_id": p["id"],
47 "title": p["title"],
48 "handle": p["handle"],
49 "vendor": p.get("vendor", ""),
50 "product_type": p.get("product_type", ""),
51 "tags": ", ".join(p.get("tags", [])),
52 "created_at": p.get("created_at", ""),
53 "updated_at": p.get("updated_at", ""),
54 "image_url": p["images"][0]["src"] if p.get("images") else "",
55 }
56 for v in p.get("variants", []):
57 row = {**base}
58 row["variant_id"] = v["id"]
59 row["variant_title"] = v.get("title", "")
60 row["sku"] = v.get("sku", "")
61 row["price"] = v.get("price", "")
62 row["compare_at_price"] = v.get("compare_at_price", "")
63 row["available"] = v.get("available", "")
64 rows.append(row)
65 return rows
66if __name__ == "__main__":
67 STORE_URL = "https://allbirds.com" # Change this to your target store
68 OUTPUT_CSV = "shopify_products.csv"
69 OUTPUT_EXCEL = "shopify_products.xlsx"
70 print(f"Scraping {STORE_URL}...")
71 products = scrape_shopify(STORE_URL)
72 print(f"\nTotal products scraped: {len(products)}")
73 print("Flattening to variant-level rows...")
74 rows = flatten_to_variants(products)
75 df = pd.DataFrame(rows)
76 print(f"DataFrame: {df.shape[0]} rows x {df.shape[1]} columns")
77 df.to_csv(OUTPUT_CSV, index=False, encoding="utf-8-sig")
78 df.to_excel(OUTPUT_EXCEL, index=False, engine="openpyxl")
79 print(f"\nExported to {OUTPUT_CSV} and {OUTPUT_EXCEL}")
Uruchom go poleceniem python scrape_shopify.py. W przypadku Allbirds zajmuje to około 45 sekund i tworzy CSV z ponad 5 000 wierszy (po jednym na wariant). Wyjście w terminalu wygląda mniej więcej tak:
1Scraping https://allbirds.com...
2 Page 1... 250 products (total: 250)
3 Page 2... 250 products (total: 500)
4 ...
5 Page 6... 170 products (total: 1420)
6Total products scraped: 1420
7Flattening to variant-level rows...
8DataFrame: 5680 rows x 14 columns
9Exported to shopify_products.csv and shopify_products.xlsx
Pomiń Pythona: scrapuj Shopify w 2 kliknięciach z Thunderbit (alternatywa no-code)
Nie każdy chce instalować Pythona, debugować błędy importów albo utrzymywać skrypt do scrapingu. Dla handlowca, który potrzebuje danych o cenach konkurencji na jutro rano, Python bywa zwyczajnie przesadą.
Właśnie dlatego stworzyliśmy — AI web scraper działający jako rozszerzenie Chrome. Bez kodu, bez kluczy API, bez konfiguracji środowiska.
Jak Thunderbit scrapuje sklepy Shopify
Thunderbit ma dedykowany Szablon Shopify Scraper, który jest wstępnie skonfigurowany pod strony produktowe Shopify. Instalujesz , przechodzisz do sklepu Shopify i klikasz „Scrape”. Szablon automatycznie wyciąga nazwy produktów, opisy, ceny, dane wariantów, obrazy i informacje o dostawcy.
W przypadku sklepów, gdzie szablon nie pasuje idealnie (niestandardowe motywy, nietypowe układy), funkcja AI Suggest Fields analizuje stronę i automatycznie generuje nazwy kolumn. Możesz je potem dostosować — zmienić nazwy, dodać pola, wpisać instrukcje typu „wyciągaj tylko produkty z ustawioną wartością compare_at_price”.
Kilka funkcji, które odpowiadają temu, co robi skrypt w Pythonie:
- Scraping podstron: automatycznie odwiedza każdą stronę produktu i wzbogaca tabelę o pełne opisy, opinie lub szczegóły wariantów — to samo, co robi nasz skrypt Python, tylko bez kodu.
- Automatyczna paginacja: obsługuje paginację klikaniem i nieskończone przewijanie bez dodatkowej konfiguracji.
- Scraping cykliczny: ustaw zadania cykliczne (np. „co poniedziałek o 9:00”) do stałego monitoringu cen — bez cron joba i bez serwera.
- Bezpłatny eksport do CSV, Excela, Google Sheets, Airtable lub Notion w każdym planie.
Skrypt Python vs Thunderbit: uczciwe porównanie
| Czynnik | Skrypt Python | Thunderbit (No-Code) |
|---|---|---|
| Czas konfiguracji | 15–60 min (środowisko + kod) | ok. 2 min (instalacja rozszerzenia Chrome) |
| Wymagany kod | Tak (Python) | Nie |
| Personalizacja | Nieograniczona | Sugestie pól AI + własne prompty |
| Obsługa paginacji | Trzeba zakodować ręcznie | Automatyczna |
| Format eksportu | Trzeba zaimplementować samemu (CSV/Excel) | CSV, Excel, Google Sheets, Airtable, Notion (bezpłatnie) |
| Zadania cykliczne | Cron job + hosting | Wbudowany harmonogram |
| Obsługa limitów | Trzeba napisać retry/backoff | Obsługiwane automatycznie |
| Najlepsze dla | Programistów, dużych pipeline’ów danych | Użytkowników biznesowych, szybkich ekstrakcji, regularnego monitoringu |
Używaj Pythona, gdy potrzebujesz pełnej kontroli albo integrujesz scraper z większym pipeline’em danych. Thunderbit wybierz wtedy, gdy zależy Ci na szybkości i nie chcesz utrzymywać kodu. Jeśli chcesz zobaczyć więcej o , przygotowaliśmy osobny przewodnik na ten temat.

Wskazówki i dobre praktyki przy scrapowaniu sklepów Shopify
Te zasady obowiązują niezależnie od narzędzia:
- Zawsze używaj
?limit=250, aby ograniczyć liczbę żądań. Domyślne 30 elementów na stronę oznacza 8 razy więcej zapytań dla tych samych danych. - Szanuj sklep: wprowadzaj 1–2 sekundowe przerwy między żądaniami. Zasypywanie serwera seriami zapytań to zła praktyka i zwiększa ryzyko blokady.
- Najpierw sprawdź
robots.txt: domyślny plikrobots.txtw Shopify NIE blokuje/products.json. Ale niektóre sklepy dodają własne reguły, więc warto to zweryfikować przed scrapingiem na większą skalę. - Najpierw zapisuj surowy JSON lokalnie, a dopiero potem go przetwarzaj. Jeśli później zmienisz logikę parsowania, nie będziesz musiał ponownie pobierać danych. Proste
json.dump(all_products, open("raw_data.json", "w"))przed spłaszczaniem oszczędza sporo problemów. - Deduplikuj po
product.id: przy paginacji czasem zdarzają się duplikaty na granicach stron. Szybkiedf.drop_duplicates(subset=["product_id", "variant_id"])usuwa ten problem. - Rzutuj
pricena float przed wykonywaniem obliczeń. Shopify zwraca ceny jako stringi („185.00”), a nie liczby. - Monitoruj zmiany w endpointach: choć
/products.jsondziała stabilnie od lat, Shopify teoretycznie mógłby go ograniczyć. Jeśli scraper nagle zacznie zwracać 404, najpierw sprawdź sklep ręcznie.
Więcej o budowaniu solidnych scraperów znajdziesz w naszym poradniku o .
Aspekty prawne i etyczne scrapowania Shopify
Krótka sekcja, ale ważna.
Endpoint /products.json udostępnia publicznie dostępne dane produktowe — te same informacje, które widzi każdy odwiedzający sklep. Regulamin Shopify zawiera zapisy o zakazie używania „automated means” do dostępu do „the Services”, ale odnosi się to do samej platformy (panelu administracyjnego, checkoutu), a nie publicznych danych sklepu. Do kwietnia 2026 nie odnotowano żadnych pozwów związanych ze scrapingiem Shopify.
Najważniejsze precedensy prawne wspierające scraping danych publicznych: sprawa hiQ v. LinkedIn potwierdziła, że scrapowanie publicznie dostępnych danych nie narusza CFAA, a Meta v. Bright Data (2024) orzekła, że ograniczenia wynikające z regulaminu obowiązują tylko wtedy, gdy użytkownik jest zalogowany.
Dobre praktyki:
- Pobieraj tylko publicznie dostępne dane produktowe
- Nie zbieraj danych osobowych ani danych klientów
- Respektuj
robots.txti limity żądań - Przestrzegaj GDPR/RODO i CCPA, jeśli przetwarzasz jakiekolwiek dane osobowe (dane katalogowe produktów nie są danymi osobowymi)
- Identyfikuj się jasnym stringiem User-Agent
- Scrapowanie własnego sklepu Shopify przez Admin API jest zawsze w porządku
Jeśli chcesz zgłębić temat, przeczytaj nasz wpis o .
Podsumowanie i najważniejsze wnioski
Publiczny endpoint Shopify /products.json sprawia, że pozyskiwanie danych e-commerce jest wyjątkowo proste. Proces wygląda tak: dopisz /products.json → pobierz dane w Pythonie → przechodź przez strony z ?limit=250&page= → spłaszcz JSON w pandas → wyeksportuj do CSV lub Excela.
Co ten przewodnik pokazuje, a czego nie ma u konkurencji:
- Pełna dokumentacja pól: wiesz dokładnie, jakie dane są dostępne (ponad 40 pól w produktach, wariantach i obrazach), zanim napiszesz choćby jedną linię kodu
- Dodatkowe endpointy:
/collections.jsoni/meta.jsondają wgląd w kategorie i metadane sklepu, czego nie opisuje większość poradników - Techniki gotowe do produkcji: ponowne użycie sesji, exponential backoff, nagłówki User-Agent i
?limit=250do obsługi realnych limitów - Prawidłowy eksport CSV/Excel: spłaszczone dane na poziomie wariantów z pandas, a nie tylko surowy zrzut JSON
- Alternatywa no-code: dla osób, które wolą szybkość niż elastyczność kodu
Jeśli chcesz jednorazowo lub cyklicznie pobierać dane z Shopify bez kodowania, wypróbuj — szablon Shopify Scraper obsługuje wszystko od paginacji po eksport. Jeśli budujesz własne pipeline’y danych albo scrapujesz wiele sklepów na dużą skalę, skrypt Python z tego przewodnika daje Ci pełną kontrolę.
Sprawdź też nasz , gdzie znajdziesz materiały wideo, albo zajrzyj do poradników o i , żeby poznać podobne techniki.
FAQ
Czy można scrapować każdy sklep Shopify za pomocą products.json?
Większość sklepów Shopify domyślnie udostępnia ten endpoint — w testach około 71% zwracało poprawny JSON. Niektóre sklepy z niestandardową konfiguracją lub dodatkowymi zabezpieczeniami (Cloudflare, headless) mogą zwrócić 404 albo zablokować żądanie. Szybki test: wejdź na {store-url}/products.json w przeglądarce. Jeśli widzisz JSON, wszystko działa.
Czy scrapowanie sklepów Shopify jest legalne?
Publiczne dane produktowe (ceny, tytuły, obrazy, opisy) są zazwyczaj dostępne, a orzeczenia takie jak hiQ v. LinkedIn wspierają scrapowanie publicznie dostępnych informacji. Mimo to zawsze sprawdź regulamin konkretnego sklepu oraz lokalne przepisy. Nie zbieraj danych osobowych ani danych klientów i respektuj limity żądań.
Ile produktów można pobrać ze sklepu Shopify?
Nie ma twardego limitu całkowitej liczby produktów. Paginacja z ?limit=250&page= pozwala pobrać cały katalog. W bardzo dużych sklepach (25 000+ produktów) warto użyć ponownego wykorzystania sesji i opóźnień, aby uniknąć limitów. Endpoint /meta.json może od razu podać dokładną liczbę produktów, więc wiesz, ile stron będzie potrzebnych.
Jaka jest różnica między products.json a Shopify Admin API?
/products.json to publiczny endpoint — bez autoryzacji, tylko do odczytu, dostępny dla każdego. Admin API wymaga tokenów właściciela sklepu i udostępnia zamówienia, stany magazynowe, dane klientów oraz możliwość zapisu. Jeśli potrzebujesz danych o sprzedaży lub rzeczywistych stanów magazynowych, potrzebujesz dostępu do Admin API (czyli musisz być właścicielem sklepu albo mieć jego zgodę).
Czy mogę scrapować Shopify bez Pythona?
Oczywiście. Narzędzia takie jak pozwalają scrapować sklepy Shopify z poziomu rozszerzenia Chrome, bez kodu. Automatycznie obsługują paginację i eksportują dane bezpośrednio do CSV, Excela, Google Sheets, Airtable lub Notion. Dla programistów preferujących inne języki ten sam endpoint /products.json działa też z JavaScriptem, Ruby, Go — właściwie z każdym językiem, który potrafi wysłać żądanie HTTP i sparsować JSON.
Dowiedz się więcej