Tony Wang7 Min. LesezeitShopify-Stores scrapen in 2026 (API & Python)
Drei Wege, Products und Collections aus Shopify-Stores 2026 zu scrapen — DIY-Python, No-Code-Tools oder strukturierte API, samt Rechtsgrundlagen.
Der schnellste Weg, Shopify-Stores in 2026 zu scrapen, ist der Aufruf einer strukturierten API, die normalisiertes JSON zurückgibt — Products, Varianten, Preise, Collections und Store-Metadaten — anstatt jede Storefront selbst zu crawlen und zu parsen. DIY in Python ist möglich, weil die meisten Shopify-Stores einen öffentlichen Products-Feed bereitstellen, aber das Handling von Varianten, die Pagination und Store-spezifische Eigenheiten machen einen gepflegten Endpoint im großen Maßstab zum einfacheren Weg.
Shopifys eigene Admin- und Storefront-APIs erfordern die Zugangsdaten des Store-Besitzers — sie sind für Stores gedacht, die du selbst kontrollierst. Um Storefronts zu untersuchen, die dir nicht gehören, sammelst du die öffentliche Product-Oberfläche, und genau die normalisiert eine strukturierte Scraping-API für dich.
Ist es legal, Shopify-Stores zu scrapen?
Product-Seiten von Storefronts sind öffentlich, und das Sammeln öffentlicher Daten wird in der Regel anders behandelt als der Zugriff auf private Accounts — mit den üblichen Bedingungen:
- Sammle nur öffentliche Storefront-Daten — keinen Admin- oder Checkout-Zugriff.
- Respektiere die Nutzungsbedingungen und robots-Direktiven jedes Stores sowie dein lokales Recht.
- Verwende Product-Bilder oder Texte nicht über das hinaus weiter, was dein Anwendungsfall und das Gesetz erlauben.
- Du bist für die rechtmäßige und redliche Nutzung dessen verantwortlich, was du sammelst.
Keine Rechtsberatung — den vollständigen Überblick findest du in Ist Web Scraping in 2026 legal?.
Option 1: DIY in Python (und warum es kaputtgeht)
Viele Shopify-Stores stellen einen öffentlichen products.json-Feed bereit, deshalb sieht der erste Versuch leicht aus:
import csv, requests
resp = requests.get(
"https://www.allbirds.com/products.json",
params={"limit": 250, "page": 1}, # walk page=1,2,... until the list is empty
headers={"User-Agent": "Mozilla/5.0"},
)
rows = []
for p in resp.json()["products"]:
for v in p["variants"]: # flatten nested variants into rows
rows.append({"title": p["title"], "handle": p["handle"],
"variant": v["title"], "price": v["price"], "available": v["available"]})
with open("shopify.csv", "w", newline="") as f:
w = csv.DictWriter(f, fieldnames=rows[0].keys()); w.writeheader(); w.writerows(rows)
# ...then handle HTTP 430 rate limits and stores that disable /products.json
Wo es teuer wird:
- Uneinheitliche Bereitstellung — manche Stores schalten den öffentlichen Feed ab, und Shopify gibt HTTP
430zurück, wenn du sein Rate-Limit erreichst, also brauchst du Backoff, Proxys und Fallbacks. - Varianten flachklopfen — jedes Product hat verschachtelte Varianten, Optionen und Bilder, die in Zeilen normalisiert werden müssen.
- Pagination —
/products.jsonliefert maximal 250 pro Seite; große Kataloge erstrecken sich über viele Seiten, die es abzugehen und zu deduplizieren gilt, und/collections.jsonist ein zweiter Crawl. - Store-spezifische Unterschiede — Währungen, Verfügbarkeit und Metafields variieren je nach Theme.
Option 2: No-Code- und Fertig-Tools
Point-and-Click-Exporter können einen einzelnen Store abziehen, aber Katalog- und Preisüberwachung bedeutet, viele Stores nach Zeitplan erneut zu prüfen und den Verlauf zu speichern — eine Pipeline, die eine API besser bedient als ein manuelles Tool.
Option 3: Eine strukturierte Shopify-API
Crawloras Shopify-API fasst Product-, Collection- und Store-Endpoints hinter einem API-Key zusammen und gibt normalisiertes JSON zurück. Richte sie auf eine Store-URL:
curl -G "https://api.crawlora.net/api/v1/shopify/products" \
-H "x-api-key: $CRAWLORA_API_KEY" \
--data-urlencode "url=https://www.allbirds.com" \
--data-urlencode "limit=50"
import requests
resp = requests.get(
"https://api.crawlora.net/api/v1/shopify/products",
headers={"x-api-key": "YOUR_API_KEY"},
params={"url": "https://www.allbirds.com", "limit": 50},
)
for product in resp.json()["data"]["products"]:
print(product["title"], product["price"], product["handle"])
Eine Response ist normalisiertes JSON, das du direkt speichern kannst (die Felder dienen zur Veranschaulichung — bestätige das Schema in den Docs):
{
"code": 200,
"msg": "OK",
"data": {
"products": [
{
"handle": "wool-runner",
"title": "Wool Runner",
"price": 98.0,
"currency": "USD",
"available": true,
"variants": [{ "title": "US 9", "price": 98.0, "available": true }]
}
]
}
}
Von dort aus kannst du den Katalog mit Collections abbilden, das vollständige Product-Detail per Handle abrufen oder Store-Metadaten auslesen — alles über denselben Key (jeder Endpoint nimmt die Store-url):
h = {"x-api-key": "YOUR_API_KEY"}
base, store = "https://api.crawlora.net/api/v1/shopify", "https://www.allbirds.com"
collections = requests.get(f"{base}/collections", headers=h, params={"url": store}).json()["data"]
product = requests.get(f"{base}/products/wool-runner", headers=h, params={"url": store}).json()["data"]
meta = requests.get(f"{base}/store", headers=h, params={"url": store}).json()["data"]
Nutze /collections/{handle}/products, um eine einzelne Collection abzugehen, und die Sitemap-Endpoints, um jede Product- und Collection-URL der Storefront zu entdecken — praktisch, wenn /products.json abgeschaltet ist.
Headless-Shopify-Storefronts und Facetten
/products.json deckt die meisten Stores ab, aber nicht alle. Manche Händler betreiben einen Headless-Storefront — ein Next.js- oder React-Frontend, das Seiten serverseitig gegen ein Shopify-Katalog-Backend rendert, aber weder den klassischen Feed noch eine auffindbare *.myshopify.com-Domain offenlegt. Dieselben Endpunkte behandeln beide Store-Typen transparent: dieselbe url, kein zusätzliches Flag. Sind der klassische Feed und der myshopify-Domain-Fallback beide nicht verfügbar, parst die API stattdessen die eingebettete Suchergebnis-Payload des Storefronts selbst.
Ein Live-Beispiel: Gymsharks US-Storefront www.gymshark.com ist ein klassischer Shopify-Store — /products.json löst normal auf. Der internationale Storefront row.gymshark.com ist headless: /products.json und /collections.json schlagen beide fehl, und nirgends auf der Seite taucht eine myshopify-Domain auf. Darunter liegt trotzdem ein Shopify-Katalog, und derselbe Aufruf funktioniert unverändert:
curl -G "https://api.crawlora.net/api/v1/shopify/collections/leggings/products" \
-H "x-api-key: $CRAWLORA_API_KEY" \
--data-urlencode "url=https://row.gymshark.com" \
--data-urlencode "limit=3"
import requests
resp = requests.get(
"https://api.crawlora.net/api/v1/shopify/collections/leggings/products",
headers={"x-api-key": "YOUR_API_KEY"},
params={"url": "https://row.gymshark.com", "limit": 3},
)
data = resp.json()["data"]
print(data["transport_mode"], data["total_items"], data["total_pages"])
Dieser Aufruf liefert echte Listing- und Facettendaten für die Collection (zum Zeitpunkt des Schreibens 186 Produkte auf 4 Seiten), markiert mit transport_mode: "ssr_embedded":
{
"code": 200,
"msg": "OK",
"data": {
"store_url": "https://row.gymshark.com",
"source_url": "https://row.gymshark.com",
"collection": "leggings",
"page": 1,
"limit": 3,
"total_items": 186,
"total_pages": 4,
"transport_mode": "ssr_embedded",
"products": [ /* 3 Produkte, jedes wie das Produkt unten aufgebaut */ ],
"facets": {
"fit": { "regular": 128, "tall": 18, "short": 10 },
"canonicalColour": { "black": 90, "pink": 12 }
},
"facets_stats": {
"price": { "min": 27, "max": 85, "avg": 56.46 }
}
}
}
facets bildet ein Filterfeld auf seine Wert-zu-Anzahl-Buckets ab — dieselben Daten, die die Filter-Sidebar des Storefronts selbst antreiben — und facets_stats liefert min/max/avg für numerische Felder wie den Preis. Die Facetten-Feldnamen spiegeln, was der Storefront selbst verwendet (Gymsharks eigene Felder sind camelCase, etwa canonicalColour); behandle sie also als store-spezifisch statt als feste Liste. Beide entfallen komplett, wenn die Payload eines Storefronts keine Facettendaten enthält.
Produkte aus einem Headless-Storefront tragen außerdem Felder, die der klassische Feed nie zurückgibt: colour, canonical_colour, discount_percentage, rating, rating_count, collection_tags, labels und pro Variante inventory_quantity. Hier ein echtes Beispiel, direkt von der Produktseite auf row.gymshark.com:
{
"handle": "gymshark-train-t-shirt-ss-tops-black-aw26",
"title": "Train T-Shirt",
"price": 35,
"colour": "black",
"canonical_colour": "black",
"rating": 4.2,
"rating_count": 1549,
"collection_tags": ["all-products", "new-releases"],
"labels": ["new"],
"variants": [
{ "title": "XS", "price": 35, "available": true, "inventory_quantity": 16 }
]
}
Kein separater Transport zu konfigurieren — dieselbe Basis-URL, derselbe x-api-key-Header, dieselben Parameter wie beim klassischen Pfad oben.
Derselbe Fallback deckt über die Listings hinaus drei weitere Endpunkte ab: Produktempfehlungen (intent=related oder intent=complementary, dieselben Parameter wie beim klassischen Pfad), statische Seiten (aus dem CMS des Storefronts selbst geparst statt aus einem /pages.json-Feed) und die Collections-Liste (aus der eigenen Sitemap des Storefronts aufgezählt). Dieselbe url, keine Flags:
curl -G "https://api.crawlora.net/api/v1/shopify/products/gymshark-train-t-shirt-ss-tops-black-aw26/recommendations" \
-H "x-api-key: $CRAWLORA_API_KEY" \
--data-urlencode "url=https://row.gymshark.com" \
--data-urlencode "intent=related"
Ein Vorbehalt zur Collections-Liste: Ohne /collections.json-Feed ist title eine Best-Effort-Ableitung aus dem URL-Slug (all-products → „All Products“), nicht der echte Anzeigename des Storefronts, und es gibt keine Produktanzahl pro Collection — geringere Genauigkeit als beim klassischen Pfad. Nutze sie zur Entdeckung und bestätige die Details mit /shopify/collections/{handle}/products.
Ergebnisse sortieren und filtern
Bei einem Headless-Storefront akzeptieren /shopify/products und /shopify/collections/{handle}/products zusätzlich einen sortBy-Parameter sowie Filterparameter pro Facette, die genau so an den Suchindex des Storefronts weitergereicht werden, wie es dessen eigene Sortier-/Filter-UI tun würde. sortBy ist sortLTH (Preis aufsteigend), sortHTL (Preis absteigend) oder newest; Filter sind ein Query-Parameter pro Facetten-Feldname (dieselben Namen, die im facets-Feld des Listings auftauchen), kommagetrennt für mehrere Werte innerhalb einer Facette und mit & über Facetten hinweg kombiniert:
curl -G "https://api.crawlora.net/api/v1/shopify/collections/leggings/products" \
-H "x-api-key: $CRAWLORA_API_KEY" \
--data-urlencode "url=https://row.gymshark.com" \
--data-urlencode "sortBy=sortLTH" \
--data-urlencode "fit=regular" \
--data-urlencode "limit=5"
Echte Zahlen aus der Leggings-Collection von row.gymshark.com (186 Produkte ungefiltert): Sortieren nach sortLTH liefert als erste fünf 21, 21, 27, 33, 33 (nicht fallend); sortHTL liefert 85, 85, 85, 81, 76.5. Der Filter fit=regular allein verengt total_items von 186 auf 128; canonicalColour=black obendrauf verengt weiter auf 34 — eine echte serverseitige Einschränkung, kein clientseitiger UI-Zustand. Die Antwort spiegelt zurück, was tatsächlich angewendet wurde:
{
"total_items": 34,
"sort": "sortLTH",
"filters": { "fit": ["regular"], "canonicalColour": ["black"] }
}
Klassische Shopify-Stores lehnen sortBy und Filter mit einem typisierten 400-Fehler ab, statt sie stillschweigend zu ignorieren. Das ist kein fehlendes Feature auf unserer Seite — Shopifys eigener öffentlicher /products.json-Feed hat überhaupt keine serverseitige Sortierung oder Filterung. Fragt man das JSON desselben klassischen Stores mit sort_by=price-ascending und mit sort_by=price-descending ab, kommt eine byteidentische Produktreihenfolge zurück; sortiert wird nur in der eigenen Seite des Themes (oder über die Storefront API, die die Zugangsdaten des Stores braucht). Ein Aufruf von www.gymshark.com (ein klassischer Store) mit gesetztem sortBy liefert deshalb einen Fehler statt einer Antwort, die sortiert aussieht, es aber nicht ist:
{ "code": 400, "msg": "sort and filters are only supported for headless storefronts served via the embedded-SSR-JSON fallback transport (transport_mode ssr_embedded); Shopify's classic public catalog JSON has no server-side sort or filter support" }
Brauchst du Sortierung oder Filter bei einem klassischen Store, wende sie nach dem Abruf clientseitig an — genau das tut das Theme des Storefronts auch.
Was du sammeln kannst
- Products: Titel, Handle, Preis, Verfügbarkeit, Bilder und Varianten
- Collections und die Products innerhalb einer Collection
- Store-Metadaten und Storefront-Sitemaps
- Suchvorschläge und Product-Empfehlungen
Grenzen und typische Herausforderungen
- Nicht jeder Store stellt den Feed bereit. Manche schalten
/products.jsonab oder rate-limiten es (HTTP430); der Store-Endpoint kann auf eine öffentliche*.myshopify.com-Domain zurückfallen, aber die Abdeckung ist nicht garantiert — nutze die Sitemap-Endpoints als Backup zur Entdeckung. - Varianten und Metafields. Products verschachteln Varianten, Optionen und Bilder; klopfe sie in Zeilen flach und rechne damit, dass sich Theme-spezifische Metafields zwischen Stores unterscheiden.
- Pagination. Products und Collections werden mit maximal 250 pro Seite paginiert; gehe sie ab und dedupliziere über die Seiten hinweg.
- Bilder und Texte sind urheberrechtlich geschützt. Preise und Verfügbarkeit sind Fakten, die du sammeln kannst; Product-Fotos und -Beschreibungen unterliegen dem Urheberrecht — veröffentliche sie nicht über das hinaus weiter, was dein Anwendungsfall und das Gesetz erlauben.
Quellen
Wo das hineinpasst
Probier es zuerst kostenlos aus: Lass eine beliebige öffentliche URL durch den Free Web Scraper laufen oder prüfe mit dem Anti-Bot-Checker, ob eine Site Bots blockiert — ohne Anmeldung.
Shopify-Daten treiben Katalogüberwachung, Preisbeobachtung von Wettbewerbern und Sortimentsanalyse an. Kombiniere sie mit der Shop.app-API für die Sicht auf den Consumer-Marketplace und der Amazon-Scraping-API für kanalübergreifende Preise, alles unter dem Workflow E-Commerce-Product-Intelligence. Für dieselbe Vorgehensweise auf anderen Marktplätzen siehe wie man Amazon-Product-Daten scrapt und wie man eBay scrapt, oder wie man eine Web-Scraping-API auswählt.
Leg los, indem du den Endpoint im Playground testest, das Request- und Response-Schema in den API-Docs liest und die Credit-Kosten auf der Preisseite durchgehst.
Häufig gestellte Fragen
Kann ich Shopify-Stores scrapen, ohne blockiert zu werden?
Crawlora übernimmt Proxy-Routing, Taktung, Retries und Fallbacks hinter der API und gibt normalisiertes JSON zurück — auch für Stores, die rate-limiten (HTTP 430) oder den öffentlichen Products-Feed abschalten.
Hat jeder Shopify-Store einen products.json-Feed?
Die meisten schon — /products.json ist ein Endpoint ohne Zugangsdaten, das bis zu 250 Products pro Seite zurückgibt —, aber manche Stores schalten es ab oder rate-limiten es (HTTP 430). Wenn die Vanity-Domain es blockiert, kann Crawlora auf eine öffentliche *.myshopify.com-Domain zurückfallen, und die Sitemap-Endpoints entdecken als Backup die Product- und Collection-URLs.
Hat Shopify nicht bereits eine API?
Shopifys Admin- und Storefront-APIs erfordern die Zugangsdaten des Store-Besitzers und sind für Stores gedacht, die du selbst kontrollierst. Um Storefronts zu untersuchen, die dir nicht gehören, sammelt Crawlora die öffentliche Product-Oberfläche als normalisiertes JSON.
Welche Daten kann ich sammeln?
Products mit Varianten, Preisen, Verfügbarkeit und Bildern; Collections und die Products darin; Store-Metadaten; statische Seiten; Storefront-Sitemaps; Suchvorschläge; und Product-Empfehlungen. Preise und Verfügbarkeit sind Fakten; Product-Bilder und -Texte sind urheberrechtlich geschützt.
Wie ziele ich auf einen bestimmten Store?
Übergib die Store-URL an das Products-Endpoint. Nutze den Product-Handle (mit der Store-url) für das vollständige Detail, das Collections-Endpoint, um die Katalogstruktur abzubilden, und die Sitemap-Endpoints, um URLs aufzuzählen.
Kann ich Preise und Katalogänderungen überwachen?
Ja. Führe Product- und Collection-Aufrufe nach Zeitplan erneut aus und speichere den Verlauf, um Preisbewegungen und Sortimentsänderungen zu verfolgen.