Zautomatyzuj badanie rynku: jak pobierać dane ze Shopify w Pythonie

Ostatnia aktualizacja: April 16, 2026

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życiaKto zyskujeCo otrzymujesz
Monitoring cen konkurencjiZespoły e-commerceŚledzenie zmian cen, promocji i cen porównawczych w katalogach konkurencji
Badanie produktów i sourcingZakupy / merchandisingPorównanie cech produktów, wariantów, materiałów i dostępności
Generowanie leadówZespoły sprzedażyPozyskiwanie nazw dostawców, danych marek i informacji kontaktowych z katalogów sklepów
Analiza rynku i kategoriiZespoły marketingoweZrozumienie miksu produktów, tagów, struktury kolekcji i pozycjonowania
Śledzenie stanów i dostępnościZespoły supply chainMonitorowanie statusu dostępności wariantów (available: true/false) w czasie
Wykrywanie nowych produktówZespoły produktoweAnaliza 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

PoleTyp danychPrzykładZastosowanie biznesowe
idInteger123456789Unikalny identyfikator produktu do deduplikacji
titleString"Classic Blue Jeans"Nazwa produktu do katalogów i porównań
handleString"classic-blue-jeans"Slug URL — buduj linki do produktu jako {store}/products/{handle}
body_htmlString (HTML) lub null

Our best-selling...

Opis produktu do analizy treści i badań SEO
vendorString"Hiut Denim"Nazwa marki/dostawcy do generowania leadów lub sourcingu
product_typeString"Jeans"Kategoryzacja do analizy rynku
created_atISO DateTime"2024-01-15T10:30:00-05:00"Śledzenie momentu dodania produktu (wykrywanie nowości)
updated_atISO DateTime"2025-03-01T08:00:00-05:00"Wykrywanie ostatnich zmian w katalogu
published_atISO DateTime"2024-01-16T00:00:00-05:00"Informacja, kiedy produkt pojawił się w sklepie
tagsArray of Strings["organic", "women", "straight-leg"]Analiza słów kluczowych/tagów pod SEO, klasyfikację i trendy
variantsArray of Objects(patrz pola wariantów poniżej)Cena, SKU i dostępność każdego wariantu
imagesArray of Objects(patrz pola obrazów poniżej)Adresy zdjęć produktów do katalogów i analizy wizualnej
optionsArray of Objects[{"name": "Size", "values": ["S","M","L"]}]Zrozumienie konfiguracji produktu (rozmiar, kolor, materiał)

Pola na poziomie wariantu (zagnieżdżone w produkcie)

PoleTyp danychPrzykładZastosowanie
idInteger987654321Unikalny identyfikator wariantu
titleString"32 / Blue"Nazwa wyświetlana wariantu
skuString"HD-BLU-32"Dopasowanie SKU do systemów magazynowych
priceString"185.00"Monitorowanie cen (uwaga: to string, do obliczeń trzeba rzutować na float)
compare_at_priceString lub null"200.00"Cena wyjściowa — kluczowa do śledzenia rabatów
availableBooleantrueDostępność towaru (jedyny publicznie widoczny wskaźnik stanu)
weightFloat1.2Analiza wysyłki i logistyki
option1, option2, option3String"32", "Blue", nullPoszczególne wartości opcji
created_at, updated_atISO DateTimeŚledzenie zmian na poziomie wariantu

Pola na poziomie obrazu

PoleTyp danychPrzykładZastosowanie
idInteger111222333Unikalny identyfikator obrazu
srcString (URL)"https://cdn.shopify.com/..."Bezpośredni link do pobrania obrazu
altString lub null"Front view of jeans"Tekst alternatywny do analizy dostępności
positionInteger1Kolejność obrazów
width, heightInteger2048, 2048Wymiary 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.

shopify-data-access-methods.webp

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=250 to 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”:

PoziomTechnikaNiezawodność
Podstawowyrequests.get() + ?page=Psuje się przy dużych katalogach, może zostać zablokowany
Średnirequests.Session() + ?limit=250 + time.sleep(1) + retry dla 429Działa w większości sklepów
ZaawansowanyAsynchroniczny httpx + rotacja User-Agent + exponential backoffGotowe 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

CzynnikSkrypt PythonThunderbit (No-Code)
Czas konfiguracji15–60 min (środowisko + kod)ok. 2 min (instalacja rozszerzenia Chrome)
Wymagany kodTak (Python)Nie
PersonalizacjaNieograniczonaSugestie pól AI + własne prompty
Obsługa paginacjiTrzeba zakodować ręcznieAutomatyczna
Format eksportuTrzeba zaimplementować samemu (CSV/Excel)CSV, Excel, Google Sheets, Airtable, Notion (bezpłatnie)
Zadania cykliczneCron job + hostingWbudowany harmonogram
Obsługa limitówTrzeba napisać retry/backoffObsługiwane automatycznie
Najlepsze dlaProgramistów, dużych pipeline’ów danychUż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.

python-vs-thunderbit-comparison.webp

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 plik robots.txt w 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. Szybkie df.drop_duplicates(subset=["product_id", "variant_id"]) usuwa ten problem.
  • Rzutuj price na float przed wykonywaniem obliczeń. Shopify zwraca ceny jako stringi („185.00”), a nie liczby.
  • Monitoruj zmiany w endpointach: choć /products.json dział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.txt i 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.json i /meta.json dają 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=250 do 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.

Wypróbuj Thunderbit do scrapowania Shopify

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

Spis treści

Wypróbuj Thunderbit

Pobieraj leady i inne dane w zaledwie 2 kliknięcia. Napędzane przez AI.

Pobierz Thunderbit To za darmo
Wyciągaj dane z pomocą AI
Łatwo przenieś dane do Google Sheets, Airtable lub Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week