Shopifys /products.json-ändpunkt er en av e-handelsvärldens minst hemliga hemligheter. Lägg till den i vilken Shopify-butik som helst, så får du tillbaka strukturerad JSON — inga API-nycklar, ingen autentisering och inget behov av att bråka med djupt nästlad HTML.
Jag jobbar med -teamet, så jag lägger mycket tid på att fundera på hur folk hämtar data från webben. Och Shopify-skrapning dyker upp hela tiden — säljteam som håller koll på konkurrenters priser, e-handelsansvariga som jämför produktkataloger, inköpsteam som letar nya leverantörer. Med på Shopify och att plattformen står för ungefär , är mängden produktdata som går att samla in enorm.
Den här guiden går igenom hela processen: vad ändpunkten returnerar, hur du paginerar genom tusentals produkter, hur du hanterar begränsningar utan att bli blockerad och hur du plattar ut Shopifys nästlade JSON till en ren CSV- eller Excel-fil med pandas. Jag visar också de ändpunkter som nästan ingen annan nämner (/collections.json, /meta.json) och ett kodfritt alternativ för dig som helst skippar Python helt.
Vad är Shopifys /products.json-ändpunkt (och varför gör den skrapning enkel)?
Varje Shopify-butik har en publik ändpunkt på {store-url}/products.json som returnerar strukturerad produktdata. Inga API-nycklar. Ingen OAuth. Ingen autentisering över huvud taget. Du lägger bara till /products.json efter butikens URL och får tillbaka en JSON-array med alla produkter i katalogen.
Testa själv: öppna eller i webbläsaren. Du ser ren, strukturerad JSON med produkttitlar, priser, varianter, bilder, taggar — allt.
Jämför det med alternativet: att tolka Shopifys HTML-teman, som är djupt nästlade, inkonsekventa mellan butiker och ändras varje gång handlaren uppdaterar sitt tema. Det är ungefär så här du annars skulle behöva jobba:
HTML-metoden (smärtsam):
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>
JSON-metoden (ren):
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 vinner på konsekvens, tillförlitlighet och enkelhet vid tolkning. Ändpunkten stöder också två viktiga frågeparametrar — ?limit= (upp till 250 produkter per sida, standard är 30) och ?page= för paginering — som vi kommer att använda flitigt i koden nedan.
Viktig skillnad: det här är en publik storefront-ändpunkt, inte . Admin API kräver åtkomsttoken från butiksägaren och ger orderdata, lagernivåer och kundinformation. Den publika /products.json-ändpunkten innehåller bara läsbar produktdata som alla kan komma åt. Jag går igenom skillnaden mer i detalj längre fram, eftersom förvirringen kring detta är enorm i forum.
En brasklapp: inte alla Shopify-butiker exponerar den här ändpunkten. I mina tester returnerar ungefär 71 % av butikerna giltig JSON (allbirds.com, gymshark.com, colourpop.com och kyliecosmetics.com fungerar), medan vissa anpassade konfigurationer ger 404 (hiutdenim.co.uk, bombas.com). Snabbkollen är enkel: besök {store-url}/products.json i webbläsaren och se vad du får.
Varför skrapa Shopify med Python? Viktiga affärsanvändningsområden
Varför ens bry sig? ROI. använder nu automatiserad prisskrapning för konkurrensanalys, upp från bara 34 % år 2020. Och forskning visar att en . Datan är alltså värd riktiga pengar.
Här är de vanligaste användningsfallen jag ser:
| Användningsfall | Vem gynnas | Vad du får |
|---|---|---|
| Övervakning av konkurrentpriser | E-handels- och driftteam | Följ prisförändringar, rabatter och jämförpriser i konkurrenternas kataloger |
| Produktresearch och inköp | Inköps- / merchandisingteam | Jämför produktfunktioner, varianter, material och tillgänglighet |
| Leadgenerering | Säljteam | Extrahera leverantörsnamn, varumärkesdata och kontaktuppgifter från butikskataloger |
| Marknads- och kategorianalys | Marknadsteam | Förstå produktmix, taggar, kategoristruktur och positionering |
| Lager- och tillgänglighetsuppföljning | Supply chain-team | Följ lagerstatus på variantnivå (available: true/false) över tid |
| Identifiering av nya produkter | Produktteam | Följ created_at-tidsstämplar för att upptäcka nya lanseringar hos konkurrenter |
Python passar naturligt för det här arbetet. använder Python som sitt primära språk, och ekosystemet — requests för HTTP, pandas för datamanipulation, httpx för async — gör det enkelt att gå från "jag har en URL" till "jag har ett kalkylblad" på under 80 rader kod.
Komplett fältreferens för products.json: Alla fält förklarade
Varje konkurrerande guide visar dig title, id och handle, och går sedan vidare. Shopifys JSON-svar innehåller över 40 fält för produkter, varianter, bilder och alternativ. Att veta vad som faktiskt finns innan du skriver skrapkoden sparar dig från att behöva skrapa om senare.
Jag har sammanställt den här referensen från live-svar från /products.json hämtade den 16 april 2026. Strukturen är konsekvent hos alla butiker som exponerar ändpunkten.
Fält på produktnivå
| Fält | Datatyp | Exempelvärde | Affärsanvändning |
|---|---|---|---|
id | Heltal | 123456789 | Unik produktidentifierare för avduplicering |
title | Sträng | "Classic Blue Jeans" | Produktnamn för kataloger och jämförelser |
handle | Sträng | "classic-blue-jeans" | URL-slug — bygg produktsidor som {store}/products/{handle} |
body_html | Sträng (HTML) eller null | Our best-selling... | Produktbeskrivning för innehållsanalys och SEO-research |
vendor | Sträng | "Hiut Denim" | Varumärkes-/leverantörsnamn för leadgen eller inköp |
product_type | Sträng | "Jeans" | Kategorisering för marknadsanalys |
created_at | ISO-datetime | "2024-01-15T10:30:00-05:00" | Följ när produkter lades till (identifiera nya lanseringar) |
updated_at | ISO-datetime | "2025-03-01T08:00:00-05:00" | Upptäck nyliga ändringar i katalogen |
published_at | ISO-datetime | "2024-01-16T00:00:00-05:00" | Se när produkten gick live i butiken |
tags | Array av strängar | ["organic", "women", "straight-leg"] | Nyckelords- och tagganalys för SEO, kategorisering och trendspaning |
variants | Array av objekt | (se variantfält nedan) | Pris, SKU och tillgänglighet per variant |
images | Array av objekt | (se bildfält nedan) | Bild-URL:er för kataloger och visuell analys |
options | Array av objekt | [{"name": "Size", "values": ["S","M","L"]}] | Förstå produktens konfigurering (storlek, färg, material) |
Fält på variantnivå (nästlade under varje produkt)
| Fält | Datatyp | Exempel | Användningsfall |
|---|---|---|---|
id | Heltal | 987654321 | Unik variantidentifierare |
title | Sträng | "32 / Blue" | Visningsnamn för varianten |
sku | Sträng | "HD-BLU-32" | SKU-matchning för lagersystem |
price | Sträng | "185.00" | Prisövervakning (obs: det är en sträng, konvertera till float för beräkningar) |
compare_at_price | Sträng eller null | "200.00" | Ursprungligt pris — viktigt för rabattspårning |
available | Boolesk | true | Tillgänglighet i lager (den enda publika lagerindikatorn) |
weight | Flyttal | 1.2 | Analys för frakt/logistik |
option1, option2, option3 | Sträng | "32", "Blue", null | Enskilda alternativvärden |
created_at, updated_at | ISO-datetime | — | Spåra ändringar på variantnivå |
Fält på bildnivå
| Fält | Datatyp | Exempel | Användningsfall |
|---|---|---|---|
id | Heltal | 111222333 | Unik bildidentifierare |
src | Sträng (URL) | "https://cdn.shopify.com/..." | Direkt länk för nedladdning av bilden |
alt | Sträng eller null | "Front view of jeans" | Alt-text för tillgänglighetsanalys |
position | Heltal | 1 | Bildordning |
width, height | Heltal | 2048, 2048 | Bilddimensioner |
Vad som INTE finns i den publika ändpunkten
En viktig fallgrop: inventory_quantity finns INTE i publika /products.json-svar. Det här fältet togs bort från publika JSON-ändpunkter i december 2017 av säkerhetsskäl. Den enda lagerindikator du får är den booleska available-varianten på varje variant (true eller false). För att få faktiska lagerantal behöver du det autentiserade Admin API:t med butikens ägaruppgifter.
Innan du skriver din skrapkod, gå igenom tabellen och avgör vilka fält som faktiskt spelar roll för ditt användningsfall. Om du övervakar priser behöver du variants[].price, variants[].compare_at_price och variants[].available. Om du jobbar med leadgenerering ska du fokusera på vendor, product_type och tags. Filtrera därefter — din CSV blir mycket renare.
Mer än products.json: Collections, meta och andra Shopify-ändpunkter
Inga konkurrerande guider nämner dessa ändpunkter. De är viktiga för seriöst konkurrensintelligensarbete.
/collections.json — alla butikens kategorier
Returnerar alla collections (kategorier) i butiken med titlar, handles, beskrivningar och produktantal. Jag verifierade detta på zoologistperfumes.com, allbirds.com och gymshark.com — alla returnerade giltig 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}
Vill du förstå hur en konkurrent strukturerar sin katalog? Det här är ändpunkten du ska använda.
/collections/{handle}/products.json — produkter per kategori
Returnerar produkter filtrerade efter en specifik collection. Samma JSON-struktur som /products.json, men begränsad till en kategori. Det här är avgörande för kategorinivå-skrapning — kanske vill du bara bevaka en konkurrents "Sale"- eller "New Arrivals"-kollektion.
/meta.json — metadata på butiksnivå
Returnerar butiksnamn, beskrivning, valuta, land och — här är den bra delen — published_products_count. Det antalet låter dig förberäkna exakt hur många pagineringssidor du behöver: ceil(published_products_count / 250). Slipp gissa och prova dig fram med en extra tom förfrågan i slutet.
Vilken ändpunkt ska du använda?
| Det du vill ha | Ändpunkt | Behövs autentisering? |
|---|---|---|
| Alla produkter (publikt) | /products.json | Nej |
| Produkter i en specifik kategori | /collections/{handle}/products.json | Nej |
| Butiksmetadata + produktantal | /meta.json | Nej |
| Alla collections (kategorier) | /collections.json | Nej |
| Order-/försäljningsdata (endast egen butik) | Admin API /orders.json | Ja (API-nyckel) |
| Lagerantal (endast egen butik) | Admin API /inventory_levels.json | Ja |
Den återkommande forumfrågan — "Kan jag skrapa hur många enheter en konkurrent sålde?" — har ett kort svar: nej. Inte via publika ändpunkter. Försäljningsdata och lagerantal kräver det autentiserade Admin API:t, vilket betyder att du måste ha butikens ägaråtkomst. Publika ändpunkter ger dig bara produktkatalogdata.

Hur man skrapar Shopify med Python: Steg-för-steg-uppsättning
- Svårighetsgrad: Nybörjare
- Tidsåtgång: ~15 minuter (installation + första skrapning)
- Du behöver: Python 3.11+,
pip, en terminal och en Shopify-butiks-URL att skrapa
Steg 1: Installera Python och nödvändiga bibliotek
Se till att du har Python 3.11 eller senare installerat (pandas 3.0.x kräver det). Installera sedan de två bibliotek vi behöver:
1pip install requests pandas
För export till Excel behöver du också:
1pip install openpyxl
Lägg till dessa imports överst i skriptet:
1import requests
2import pandas as pd
3import time
4import random
5import json
Du ska inte få några importfel när du kör skriptet. Om pandas klagar på versionen, uppgradera Python till 3.12.
Steg 2: Hämta produktdata från /products.json
Här är en enkel funktion som tar en butik-URL, anropar ändpunkten och returnerar den tolkade JSON-datan:
1def fetch_products_page(store_url, page=1, limit=250):
2 """Hämta en sida med produkter från en Shopify-butik."""
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", [])
Viktiga detaljer:
limit=250är maxgränsen Shopify tillåter per sida. Standardvärdet är 30, så att sätta detta uttryckligen minskar antalet förfrågningar med upp till 8 gånger.User-Agent-header: Sätt alltid en realistisk sådan. Förfrågningar utan User-Agent triggar lättare Shopifys anti-bot-system.timeout=30: Låt inte en enskild förfrågan hänga för evigt.
Testa med en känd butik:
1products = fetch_products_page("https://allbirds.com")
2print(f"Hämtade {len(products)} produkter")
3print(f"Första produkten: {products[0]['title']}")
Du bör se något i stil med: Hämtade 250 produkter och titeln på den första produkten.
Steg 3: Hantera paginering för att skrapa alla produkter
En enstaka förfrågan ger som mest 250 produkter. De flesta butiker har fler än så (Allbirds har 1 420+). Du måste loopa genom sidorna tills du får ett tomt svar.
1def scrape_all_products(store_url, delay=1.0):
2 """Skrapa alla produkter från en Shopify-butik och hantera paginering."""
3 all_products = []
4 page = 1
5 while True:
6 print(f"Hämtar sida {page}...")
7 products = fetch_products_page(store_url, page=page, limit=250)
8 if not products:
9 print(f"Inga fler produkter. Totalt: {len(all_products)}")
10 break
11 all_products.extend(products)
12 print(f" Fick {len(products)} produkter (totalt hittills: {len(all_products)})")
13 page += 1
14 # Var schysst: vänta mellan förfrågningarna
15 time.sleep(delay + random.uniform(0, 0.5))
16 return all_products
När products kommer tillbaka tomt har du nått slutet.
time.sleep() med lite slumpmässig variation hjälper dig att hålla dig under Shopifys informella taktgräns (~2 förfrågningar/sekund).
Proffstips: Om du först hämtade /meta.json vet du redan det totala produktantalet och kan räkna ut exakt hur många sidor du behöver: pages = ceil(product_count / 250). Då slipper du den där "en extra tom förfrågan i slutet".
Steg 4: Tolka och välj de fält du behöver
Nu när du har alla produkter som en Python-lista av dictionaries är det dags att extrahera bara de fält du bryr dig om. Här är ett exempel som hämtar de vanligaste fälten för prisövervakning:
1def extract_product_data(products):
2 """Extrahera nyckelfält från produkter och platta till varianter."""
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
Det här skapar en rad per variant — det mest användbara formatet för prisjämförelser, eftersom en enda produkt som "Classic Blue Jeans" kan ha 12 varianter (6 storlekar × 2 färger), och varje variant har sitt eget pris och sin egen tillgänglighetsstatus.
Exportera skrapad Shopify-data till CSV och Excel med pandas
Varenda annan Shopify-skrapguide dumpar bara rå JSON i en fil och kallar det klart. Helt okej för utvecklare. Ganska värdelöst för e-handelsanalytikern som behöver ett kalkylblad före fredag.
Problemet: Shopifys JSON är nästlad. En produkt kan innehålla ett dussin varianter, var och en med eget pris, SKU och tillgänglighet. Att platta ut det till rader och kolumner kräver lite pandas-arbete.
Platta till nästlad JSON till en ren tabell
Det finns två sätt, beroende på vad du ska göra:
Alternativ A: En rad per variant (bäst för prisövervakning och lageruppföljning)
1# Använd funktionen extract_product_data från steg 4
2products = scrape_all_products("https://allbirds.com")
3rows = extract_product_data(products)
4df = pd.DataFrame(rows)
5print(f"DataFrame-form: {df.shape}")
6print(df.head())
Det här ger dig en platt tabell där varje rad är en unik kombination av produkt och variant. En butik med 500 produkter och i snitt 4 varianter per produkt ger ett DataFrame med cirka 2 000 rader.
Alternativ B: En rad per produktöversikt (bäst för katalogöversikter)
1def summarize_products(products):
2 """En rad per produkt med min/max-pris över varianterna."""
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
Exportera till CSV, Excel och Google Sheets
1# CSV-export (använd utf-8-sig så Excel klarar specialtecken)
2df.to_csv("shopify_products.csv", index=False, encoding="utf-8-sig")
3# Excel-export (kräver openpyxl)
4df.to_excel("shopify_products.xlsx", index=False, engine="openpyxl")
5print("Exporterade till shopify_products.csv och shopify_products.xlsx")
För Google Sheets kan du använda gspread med ett servicekonto, men ärligt talat — för de flesta användningsfall går det snabbare och enklare att exportera till CSV och sedan ladda upp till Google Drive.
Produktionsklar Python-skrapning: hastighetsgränser, retries och blockeringar
Det grundläggande skriptet fungerar bra för små butiker. Men ska du skrapa en butik med 5 000+ produkter, eller flera butiker i följd? Då börjar det knaka.
Förstå Shopifys hastighetsgränser och blockeringsbeteende
Shopifys publika JSON-ändpunkter har inga formellt dokumenterade rate limits (till skillnad från Admin API:s leaky bucket-modell), men empiriska tester visar:
- Säker takt: ~2 förfrågningar per sekund och butik
- Mjuk gräns: ~40 förfrågningar per minut innan throttling slår in
- HTTP 429: "Too Many Requests" — standardresponsen när du gör för många förfrågningar
- HTTP 430: En Shopify-specifik kod som signalerar blockering på säkerhetsnivå (inte bara rate limiting)
- HTTP 403 eller CAPTCHA-omdirigering: Vissa butiker med extra Cloudflare-skydd
Förfrågningar från delad molninfrastruktur (AWS Lambda, Google Cloud Run) löper särskilt stor risk att blockeras eftersom de IP-intervallen ofta missbrukas.
Tekniker för att skrapa Shopify pålitligt
Här är utvecklingen från "fungerar på min laptop" till "kör i produktion":
| Nivå | Teknik | Tillförlitlighet |
|---|---|---|
| Grundnivå | requests.get() + ?page= | Går sönder på stora kataloger, kan blockeras |
| Mellannivå | requests.Session() + ?limit=250 + time.sleep(1) + retry vid 429 | Fungerar för de flesta butiker |
| Avancerad | Asynkron httpx + roterande User-Agent + exponentiell backoff | Produktionsklar, skalar till 10K+ produkter |
Mellannivå (rekommenderas för de flesta användare):
1import requests
2from requests.adapters import HTTPAdapter
3from urllib3.util.retry import Retry
4def create_session():
5 """Skapa en requests-session med automatisk retry-logik."""
6 session = requests.Session()
7 retries = Retry(
8 total=5,
9 backoff_factor=1, # vila: 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
Retry-inställningen hanterar 429-svar automatiskt med exponentiell backoff. backoff_factor=1 betyder att vilosekvensen blir 0,5s → 1s → 2s → 4s → 8s mellan försöken. Återanvändning av session (requests.Session()) ger dessutom connection pooling, vilket minskar overhead när du gör flera förfrågningar till samma domän.
User-Agent-rotation: Om du skrapar flera butiker, rotera mellan 3–5 realistiska webbläsar-User-Agent-strängar. Det handlar inte om att lura någon — det handlar om att inte se ut som en bot som skickar identiska headers i varje anrop.
Komplett fungerande Python-skript för att skrapa Shopify med CSV-export
Här är det kompletta, färdiga skriptet som sammanför allt ovan. Det är ungefär 75 rader faktisk kod (plus kommentarer), och jag har testat det mot Allbirds (1 420 produkter), ColourPop (2 000+ produkter) och Zoologist Perfumes (liten 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 """Skapa en session med retry-logik för 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 """Skrapa alla produkter från en Shopify-butik 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" Sida {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)} produkter (totalt: {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 """Platta till nästlad produkt-JSON till en rad 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" # Byt till din målsajt
68 OUTPUT_CSV = "shopify_products.csv"
69 OUTPUT_EXCEL = "shopify_products.xlsx"
70 print(f"Skrapar {STORE_URL}...")
71 products = scrape_shopify(STORE_URL)
72 print(f"\nTotalt antal skrapade produkter: {len(products)}")
73 print("Plattar till till rader på variantnivå...")
74 rows = flatten_to_variants(products)
75 df = pd.DataFrame(rows)
76 print(f"DataFrame: {df.shape[0]} rader x {df.shape[1]} kolumner")
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"\nExporterade till {OUTPUT_CSV} och {OUTPUT_EXCEL}")
Kör det med python scrape_shopify.py. För Allbirds tar detta ungefär 45 sekunder och producerar en CSV med cirka 5 000+ rader (en per variant). Terminalutskriften ser ungefär ut så här:
1Skrapar https://allbirds.com...
2 Sida 1... 250 produkter (totalt: 250)
3 Sida 2... 250 produkter (totalt: 500)
4 ...
5 Sida 6... 170 produkter (totalt: 1420)
6Totalt antal skrapade produkter: 1420
7Plattar till till rader på variantnivå...
8DataFrame: 5680 rader x 14 kolumner
9Exporterade till shopify_products.csv och shopify_products.xlsx
Hoppa över Python: skrapa Shopify på 2 klick med Thunderbit (kodfritt alternativ)
Alla vill inte installera Python, felsöka importfel eller underhålla ett skrapskript. För säljaren som behöver konkurrentpriser till imorgon bitti är Python överkurs.
Därför byggde vi — en AI-webbskrapare som körs som ett Chrome-tillägg. Ingen kod, inga API-nycklar, ingen miljökonfiguration.
Så skrapar Thunderbit Shopify-butiker
Thunderbit har en dedikerad Shopify Scraper-mall som är förkonfigurerad för Shopify produktsidor. Du installerar , går till en Shopify-butik och klickar på "Scrape". Mallen extraherar automatiskt produktnamn, beskrivningar, priser, variantdetaljer, bilder och leverantörsinformation.
För butiker där mallen inte matchar perfekt (anpassade teman, ovanliga layouter) läser Thunderbits AI Suggest Fields-funktion sidan och skapar automatiskt kolumnnamn. Du kan anpassa dessa — byta namn på kolumner, lägga till fält, skriva instruktioner som "extrahera bara produkter med compare_at_price satt."
Några funktioner som direkt motsvarar det Python-skriptet gör:
- Undersideskrapning: Besöker automatiskt varje produktsida och berikar tabellen med fullständiga beskrivningar, recensioner eller variantdetaljer — samma sak som vårt Python-skript gör genom att iterera genom sidor, men helt utan kod.
- Automatisk paginering: Hanterar sidnavigering och oändlig scroll utan konfiguration.
- Schemalagd skrapning: Ställ in återkommande jobb (t.ex. "varje måndag kl. 09.00") för löpande prisövervakning — ingen cron-jobb eller server behövs.
- Gratis export till CSV, Excel, Google Sheets, Airtable eller Notion på alla planer.
Python-skript vs. Thunderbit: ärlig jämförelse
| Faktor | Python-skript | Thunderbit (kodfritt) |
|---|---|---|
| Installationstid | 15–60 min (miljö + kod) | ~2 min (installera Chrome-tillägg) |
| Kräver kodning | Ja (Python) | Nej |
| Anpassning | Obegränsad | AI-föreslagna fält + egna prompts |
| Hantering av paginering | Måste kodas manuellt | Automatisk |
| Exportformat | Koda själv (CSV/Excel) | CSV, Excel, Google Sheets, Airtable, Notion (gratis) |
| Schemalagda körningar | Cron-jobb + hosting | Inbyggd schemaläggare |
| Hantering av rate limits | Måste koda retries/backoff | Hanteras automatiskt |
| Bäst för | Utvecklare, stora datapipelines | Affärsanvändare, snabba extraktioner, återkommande övervakning |
Använd Python när du behöver full kontroll eller integrerar i en större datapipeline. Använd Thunderbit när du behöver data snabbt och inte vill underhålla kod. För en djupare titt på har vi skrivit en separat guide om just det.

Tips och bästa praxis för att skrapa Shopify-butiker
Det här gäller oavsett vilket verktyg du använder:
- Använd alltid
?limit=250för att minimera antalet förfrågningar. Standardvärdet 30 per sida innebär 8 gånger fler anrop för samma data. - Respektera butiken: Lägg in 1–2 sekunders fördröjning mellan förfrågningar. Att bomba en server med snabba anrop är dålig praxis och ökar risken att bli blockerad.
- Kolla
robots.txtförst: Shopifys standard-robots.txtblockerar INTE/products.json. Men vissa butiker lägger till egna regler, så kolla innan du skrapar i stor skala. - Spara rå JSON lokalt först, bearbeta sedan. Om din parser ändras senare slipper du skrapa om. En enkel
json.dump(all_products, open("raw_data.json", "w"))innan du plattar till datan sparar huvudvärk. - Avduplicera på
product.id: Paginering kan ibland ge dubbletter vid sidgränser. En snabbdf.drop_duplicates(subset=["product_id", "variant_id"])fixar det. - Konvertera
pricetill float innan du räknar. Shopify returnerar priser som strängar ("185.00"), inte tal. - Övervaka ändringar i ändpunkten: Även om
/products.jsonhar varit stabil i åratal kan Shopify i teorin begränsa den. Om din skrapare plötsligt får 404, kontrollera butiken manuellt först.
För mer om hur du bygger robusta skrapor, se vår guide om .
Juridiska och etiska överväganden vid skrapning av Shopify
Kort avsnitt, men viktigt.
/products.json-ändpunkten levererar offentligt tillgänglig produktdata — samma information som vilken besökare som helst ser i butiken. Shopifys användarvillkor innehåller språk om att inte använda "automated means" för att komma åt "the Services", men detta syftar på själva plattformen (adminpanelen, checkout), inte på offentlig storefront-data. Inga Shopify-specifika skraprättsfall har lämnats in per april 2026.
Viktiga rättsliga prejudikat stödjer skrapning av offentlig data: fallet hiQ v. LinkedIn slog fast att skrapning av offentligt tillgänglig data inte bryter mot CFAA, och Meta v. Bright Data (2024) slog fast att TOS-begränsningar bara gäller när en användare är inloggad.
Bästa praxis:
- Skrapa bara offentligt tillgänglig produktdata
- Skrapa inte person- eller kunddata
- Respektera
robots.txtoch rate limits - Följ GDPR/CCPA om du hanterar personuppgifter (produktkatalogdata är inte persondata)
- Identifiera dig med en tydlig User-Agent-sträng
- Att skrapa din egen Shopify-butik via Admin API är alltid okej
För en djupare genomgång, se vårt inlägg om .
Slutsats och viktiga lärdomar
Shopifys publika /products.json-ändpunkt gör extraktion av e-handelsdata så enkel som det kan bli. Arbetsflödet är: lägg till /products.json → hämta med Python → paginera med ?limit=250&page= → platta till med pandas → exportera till CSV eller Excel.
Den här guiden täcker sånt som andra inte gör:
- Komplett fältreferens: Se exakt vilken data som finns tillgänglig (40+ fält över produkter, varianter och bilder) innan du skriver en enda rad kod
- Ytterligare ändpunkter:
/collections.jsonoch/meta.jsonger dig kategoriinsikter och butiksmetadata som ingen konkurrerande guide tar upp - Produktionsklara tekniker: Återanvändning av sessioner, exponentiell backoff, User-Agent-header och
?limit=250för att hantera verkliga rate limits - Korrekt CSV-/Excel-export: Plattad variantdata med pandas, inte bara rå JSON-dump
- Kodfritt alternativ: för dig som föredrar snabbhet framför kodflexibilitet
För engångs- eller återkommande Shopify-uttag utan kod, testa — Shopify Scraper-mallen hanterar allt från paginering till export. För anpassade datapipelines eller skrapning i stor skala över många butiker ger Python-skriptet i den här guiden dig full kontroll.
Kolla in vår för videogenomgångar, eller utforska våra guider om och för närliggande tekniker.
Vanliga frågor
Kan man skrapa vilken Shopify-butik som helst med products.json?
De flesta Shopify-butiker exponerar den här ändpunkten som standard — i tester returnerade cirka 71 % giltig JSON. Vissa butiker med anpassade konfigurationer eller extra säkerhetslager (Cloudflare, headless-lösningar) kan ge 404 eller blockera förfrågan. Snabbtestet: besök {store-url}/products.json i webbläsaren. Om du ser JSON, då fungerar det.
Är det lagligt att skrapa Shopify-butiker?
Offentliga produktdata (priser, titlar, bilder, beskrivningar) är i regel tillgängliga, och rättsfall som hiQ v. LinkedIn stödjer skrapning av offentligt tillgänglig information. Men kolla alltid butikens egna användarvillkor och din lokala lagstiftning. Skrapa inte person- eller kunddata och respektera rate limits.
Hur många produkter kan man skrapa från en Shopify-butik?
Det finns ingen hård totalgräns. Paginering med ?limit=250&page= låter dig hämta hela katalogen. För mycket stora butiker (25 000+ produkter), använd session-återanvändning och fördröjningar för att undvika rate limits. /meta.json kan dessutom ge dig exakt produktantal i förväg så du vet hur många sidor du ska förvänta dig.
Vad är skillnaden mellan products.json och Shopify Admin API?
/products.json är en publik ändpunkt — ingen autentisering, endast läsbar produktdata, tillgänglig för alla. Admin API kräver åtkomsttoken från butiksägaren och ger orderdata, lagerantal, kunddata och skrivåtkomst. Om du behöver försäljningsdata eller faktiska lagerantal behöver du Admin API-åtkomst (vilket innebär att du måste vara butiksägare eller ha deras tillstånd).
Kan jag skrapa Shopify utan Python?
Absolut. Verktyg som låter dig skrapa Shopify-butiker via ett Chrome-tillägg utan kod. Det hanterar paginering automatiskt och exporterar direkt till CSV, Excel, Google Sheets, Airtable eller Notion. För utvecklare som föredrar andra språk fungerar samma /products.json-ändpunkt med JavaScript, Ruby, Go — vilket språk som helst som kan göra HTTP-anrop och tolka JSON.
Läs mer