Marktforschung automatisieren: Shopify mit Python scrapen

Zuletzt aktualisiert am July 13, 2026
Marktforschung automatisieren: Shopify mit Python scrapen

Shopifys /products.json-Endpunkt gehört zu den am besten gehüteten Geheimnissen im E-Commerce-Datenbereich. Hängen Sie ihn an eine beliebige Shopify-Store-URL an, und schon bekommen Sie strukturiertes JSON zurück, ohne API-Key, ohne Authentifizierung und ohne sich durch verschachteltes HTML zu kämpfen.

Ich arbeite im Team der Thunderbit Official Website, beschäftige mich also täglich damit, wie Menschen Daten aus dem Web ziehen. Und Shopify-Scraping taucht dabei immer wieder auf – von Sales-Teams, die Konkurrenzpreise im Auge behalten, über E-Commerce-Operations, die Produktkataloge vergleichen, bis zu Einkaufsteams auf Lieferantensuche. Bei 4,82 Millionen aktiven Händlern auf Shopify und einem Marktanteil von rund 30 % im US-E-Commerce liegt eine gewaltige Menge an Produktdaten zum Auslesen bereit.

Dieser Leitfaden deckt den kompletten Ablauf ab: was der Endpunkt zurückgibt, wie Sie Tausende Produkte per Paginierung abrufen, wie Sie ohne Blockierungen mit Rate Limits umgehen und wie Sie Shopifys verschachteltes JSON mit pandas in eine saubere CSV- oder Excel-Datei verwandeln. Außerdem zeige ich die Endpunkte, über die sonst kaum jemand spricht (/collections.json, /meta.json), und eine No-Code-Alternative für alle, die Python komplett umgehen wollen.

Was ist Shopifys /products.json-Endpunkt – und warum macht er Scraping so einfach?

Jeder Shopify-Store hat einen öffentlichen Endpunkt unter {store-url}/products.json, der strukturierte Produktdaten zurückliefert. Keine API-Keys. Kein OAuth. Keine Authentifizierung irgendeiner Art. Sie hängen /products.json an die Store-URL an und erhalten ein JSON-Array mit allen Produkten aus dem Katalog.

Probieren Sie es direkt aus: Öffnen Sie allbirds.com/products.json oder zoologistperfumes.com/products.json in Ihrem Browser. Sie sehen sauberes, strukturiertes JSON mit Produkttiteln, Preisen, Varianten, Bildern und Tags.

Die Alternative ist deutlich mühsamer: Shopifys HTML-Themes parsen. Die sind tief verschachtelt, von Store zu Store uneinheitlich und ändern sich, sobald ein Händler sein Theme aktualisiert. So sähe das aus:

HTML-Ansatz (unschön):

<div class="product-card__info">
  <h3 class="product-card__title">
    <a href="/products/classic-blue-jeans">Classic Blue Jeans</a>
  </h3>
  <span class="price price--on-sale" data-product-price>$149.00</span>
</div>

JSON-Ansatz (sauber):

{
  "title": "Classic Blue Jeans",
  "handle": "classic-blue-jeans",
  "vendor": "Hiut Denim",
  "variants": [{"price": "149.00", "sku": "HD-BLU-32", "available": true}]
}

JSON gewinnt bei Konsistenz, Zuverlässigkeit und einfacher Weiterverarbeitung. Der Endpunkt unterstützt außerdem zwei wichtige Query-Parameter – ?limit= (bis zu 250 Produkte pro Seite, Standard sind 30) und ?page= für die Paginierung – die wir im Code unten ausgiebig nutzen.

Wichtige Abgrenzung: Das hier ist ein öffentlicher Storefront-Endpunkt, nicht die Shopify Admin API. Die Admin API braucht Zugriffstoken des Store-Besitzers und liefert Bestelldaten, Lagerbestände und Kundendaten. Der öffentliche /products.json-Endpunkt enthält nur schreibgeschützte Produktdaten, auf die jeder zugreifen kann. Auf diesen Unterschied komme ich später noch genauer ein, weil er in Foren ständig für Verwirrung sorgt.

Wichtig: Nicht jeder Shopify-Store stellt diesen Endpunkt bereit. In meinen Tests lieferten etwa 71 % der Stores gültiges JSON (allbirds.com, gymshark.com, colourpop.com, kyliecosmetics.com funktionierten alle), während einige individuelle Setups 404 zurückgaben (hiutdenim.co.uk, bombas.com). Der Schnellcheck ist denkbar einfach: Besuchen Sie {store-url}/products.json im Browser und schauen Sie, was zurückkommt.

Warum Shopify mit Python scrapen? Die wichtigsten Business-Anwendungsfälle

Warum sich der Aufwand lohnt? Wegen des ROI. 81 % der US-Händler nutzen inzwischen automatisiertes Preisscraping für Competitive Intelligence – 2020 waren es erst 34 %. Und Studien zeigen, dass eine Verbesserung der Preisstrategie um nur 1 % im Schnitt zu 11,1 % mehr Gewinn führt. Diese Daten sind also bares Geld wert.

Diese Anwendungsfälle sehe ich am häufigsten:

AnwendungsfallWer profitiertWas Sie erhalten
Konkurrenzpreis-MonitoringE-Commerce-Operations-TeamsPreisänderungen, Rabatte und Vergleichspreise in Konkurrenzkatalogen nachverfolgen
Produktrecherche & BeschaffungEinkauf / MerchandisingProduktmerkmale, Varianten, Materialien und Verfügbarkeit vergleichen
Lead-GenerierungVertriebsteamsLieferantennamen, Markendaten und Kontaktinformationen aus Store-Katalogen extrahieren
Markt- & KategorieanalyseMarketing-TeamsProduktmix, Tags, Kategoriestruktur und Positionierung verstehen
Lager- & Verfügbarkeits-TrackingSupply-Chain-TeamsVariantenbezogenen Lagerstatus (available: true/false) über die Zeit beobachten
Erkennung neuer ProdukteProduktteamscreated_at-Zeitstempel verfolgen, um neue Launches von Wettbewerbern zu erkennen

Python ist dafür die naheliegende Wahl. 69,6 % der Entwickler im Scraping-Bereich nutzen Python als primäre Sprache, und das Ökosystem – requests für HTTP, pandas für Datenverarbeitung, httpx für Async – bringt Sie in unter 80 Codezeilen von „Ich habe eine URL“ zu „Ich habe eine Tabelle“.

Vollständige Feldübersicht für products.json: Jedes Feld erklärt

Jedes Konkurrenz-Tutorial zeigt Ihnen title, id und handle und macht dann weiter. Die JSON-Antwort von Shopify enthält aber über 40 Felder über Produkte, Varianten, Bilder und Optionen hinweg. Wenn Sie vor dem Coden wissen, was verfügbar ist, ersparen Sie sich späteres erneutes Scrapen.

Diese Referenz habe ich aus Live-Antworten von /products.json zusammengestellt, die am 16. April 2026 abgerufen wurden. Die Struktur ist bei allen Stores, die den Endpunkt bereitstellen, konsistent.

Felder auf Produktebene

FeldDatentypBeispielwertBusiness-Nutzen
idInteger123456789Eindeutige Produkt-ID zur Duplikatvermeidung
titleString"Classic Blue Jeans"Produktname für Kataloge und Vergleiche
handleString"classic-blue-jeans"URL-Slug – Produktlinks als {store}/products/{handle} aufbauen
body_htmlString (HTML) oder null

Our best-selling...

Produktbeschreibung für Inhaltsanalyse und SEO-Recherche
vendorString"Hiut Denim"Marken-/Lieferantenname für Lead-Gen oder Beschaffung
product_typeString"Jeans"Kategorisierung für Marktanalysen
created_atISO-DateTime"2024-01-15T10:30:00-05:00"Nachverfolgen, wann Produkte hinzugefügt wurden (Neuer-Launch-Erkennung)
updated_atISO-DateTime"2025-03-01T08:00:00-05:00"Kürzliche Katalogänderungen erkennen
published_atISO-DateTime"2024-01-16T00:00:00-05:00"Wissen, wann Produkte im Store live gingen
tagsArray von Strings["organic", "women", "straight-leg"]Keyword-/Tag-Analyse für SEO, Kategorisierung und Trendbeobachtung
variantsArray von Objekten(siehe Variantenfelder unten)Preis, SKU und Verfügbarkeit je Variante
imagesArray von Objekten(siehe Bildfelder unten)Bild-URLs für Kataloge und visuelle Analysen
optionsArray von Objekten[{"name": "Size", "values": ["S","M","L"]}]Produktkonfiguration verstehen (Größe, Farbe, Material)

Felder auf Variantenebene (verschachtelt unter jedem Produkt)

FeldDatentypBeispielUse Case
idInteger987654321Eindeutige Varianten-ID
titleString"32 / Blue"Anzeigename der Variante
skuString"HD-BLU-32"SKU-Abgleich für Inventarsysteme
priceString"185.00"Preis-Monitoring (Achtung: String, für Berechnungen in Float umwandeln)
compare_at_priceString oder null"200.00"Originalpreis – wichtig für Rabattverfolgung
availableBooleantrueLagerverfügbarkeit (der einzige öffentliche Lagerindikator)
weightFloat1.2Analyse für Versand und Logistik
option1, option2, option3String"32", "Blue", nullEinzelne Optionswerte
created_at, updated_atISO-DateTimeÄnderungsverfolgung auf Variantenebene

Felder auf Bildebene

FeldDatentypBeispielUse Case
idInteger111222333Eindeutige Bild-ID
srcString (URL)"https://cdn.shopify.com/..."Direkter Download-Link zum Bild
altString oder null"Front view of jeans"Alt-Text für Barrierefreiheitsanalyse
positionInteger1Reihenfolge der Bilder
width, heightInteger2048, 2048Bildabmessungen

Was im öffentlichen Endpunkt NICHT enthalten ist

Ein wichtiger Stolperstein: inventory_quantity ist in öffentlichen /products.json-Antworten NICHT verfügbar. Dieses Feld wurde im Dezember 2017 aus Sicherheitsgründen aus den öffentlichen JSON-Endpunkten entfernt. Der einzige Lagerhinweis, den Sie bekommen, ist das boolesche Feld available bei jeder Variante (true oder false). Um echte Bestandsmengen abzurufen, brauchen Sie die authentifizierte Admin API mit den Zugangsdaten des Store-Besitzers.

Bevor Sie mit dem Scraping beginnen, gehen Sie diese Tabelle durch und entscheiden Sie, welche Felder für Ihren Use Case zählen. Wer Preise überwacht, braucht variants[].price, variants[].compare_at_price und variants[].available. Wer Leads generiert, konzentriert sich auf vendor, product_type und tags. Filtern Sie entsprechend – Ihre CSV wird dadurch deutlich sauberer.

Über products.json hinaus: Collections, Meta und weitere Shopify-Endpunkte

Kein Konkurrenzleitfaden erwähnt diese Endpunkte. Für ernsthafte Competitive-Intelligence-Arbeit sind sie aber Gold wert.

/collections.json – Alle Kategorien des Stores

Gibt alle Collections (Kategorien) des Stores mit Titeln, Handles, Beschreibungen und Produktanzahlen zurück. Ich habe das auf zoologistperfumes.com, allbirds.com und gymshark.com geprüft – alle lieferten gültiges JSON.

{
  "collections": [
    {
      "id": 308387348539,
      "title": "Attars",
      "handle": "attars",
      "published_at": "2026-03-29T12:20:32-04:00",
      "products_count": 1,
      "image": { "src": "https://cdn.shopify.com/..." }
    }
  ]
}

Sie wollen verstehen, wie ein Wettbewerber seinen Katalog strukturiert? Dann ist das der richtige Endpunkt.

/collections/{handle}/products.json – Produkte nach Kategorie

Liefert Produkte, gefiltert nach einer bestimmten Collection. Gleiche JSON-Struktur wie /products.json, aber nur für eine Kategorie. Das ist besonders wichtig für Scraping auf Kategorieebene – etwa, wenn Sie nur die „Sale“- oder „New Arrivals“-Kollektion eines Wettbewerbers beobachten wollen.

/meta.json – Metadaten auf Store-Ebene

Gibt Store-Namen, Beschreibung, Währung, Land und published_products_count zurück. Damit berechnen Sie im Voraus genau, wie viele Seiten Sie für die Paginierung brauchen: ceil(published_products_count / 250). Kein endloses Hochzählen mehr, bis eine leere Antwort kommt.

Welchen Endpunkt sollten Sie verwenden?

Was Sie möchtenEndpunktAuthentifizierung nötig?
Alle Produkte (öffentlich)/products.jsonNein
Produkte in einer bestimmten Kategorie/collections/{handle}/products.jsonNein
Store-Metadaten + Produktanzahl/meta.jsonNein
Alle Collections (Kategorien)/collections.jsonNein
Bestell-/Verkaufsdaten (nur eigener Store)Admin API /orders.jsonJa (API-Key)
Lagerbestände (nur eigener Store)Admin API /inventory_levels.jsonJa

Die immer wieder auftauchende Forenfrage – „Kann ich sehen, wie viele Einheiten ein Konkurrent verkauft hat?“ – hat eine kurze Antwort: nein. Nicht über öffentliche Endpunkte. Verkaufsdaten und Bestandsmengen brauchen die authentifizierte Admin API, also Zugriff des Store-Besitzers.

shopify-data-access-methods.webp

Shopify mit Python scrapen: Schritt-für-Schritt-Einrichtung

  • Schwierigkeit: Anfänger
  • Zeitaufwand: ca. 15 Minuten (Setup + erster Scrape)
  • Was Sie brauchen: Python 3.11+, pip, ein Terminal und eine Shopify-Store-URL zum Scrapen

Schritt 1: Python und benötigte Bibliotheken installieren

Stellen Sie sicher, dass Python 3.11 oder neuer installiert ist (pandas 3.0.x setzt das voraus). Installieren Sie dann die zwei Bibliotheken, die wir brauchen:

pip install requests pandas

Für den Excel-Export benötigen Sie zusätzlich:

pip install openpyxl

Fügen Sie am Anfang Ihres Skripts diese Imports ein:

import requests
import pandas as pd
import time
import random
import json

Beim Ausführen des Skripts sollten keine Importfehler auftreten. Meldet pandas einen Versionsfehler, aktualisieren Sie Python auf 3.12.

Schritt 2: Produktdaten aus /products.json abrufen

Hier ist eine einfache Funktion, die eine Store-URL annimmt, den Endpunkt anspricht und das geparste JSON zurückgibt:

def fetch_products_page(store_url, page=1, limit=250):
    """Eine einzelne Produktseite aus einem Shopify-Store abrufen."""
    url = f"{store_url.rstrip('/')}/products.json"
    params = {"limit": limit, "page": page}
    headers = {
        "User-Agent": "Mozilla/5.0 (compatible; ProductResearch/1.0)"
    }
    
    response = requests.get(url, params=params, headers=headers, timeout=30)
    response.raise_for_status()
    return response.json().get("products", [])

Wichtige Details:

  • limit=250 ist das Maximum, das Shopify pro Seite zulässt. Der Standardwert ist 30, daher reduzieren Sie mit dieser expliziten Einstellung die Anzahl der Requests um bis zu das Achtfache.
  • User-Agent-Header: Verwenden Sie immer einen realistischen Wert. Requests ohne User-Agent lösen eher die Anti-Bot-Systeme von Shopify aus.
  • timeout=30: Lassen Sie keinen einzelnen Request ewig hängen.

Testen Sie die Funktion mit einem bekannten Store:

products = fetch_products_page("https://allbirds.com")
print(f"Fetched {len(products)} products")
print(f"First product: {products[0]['title']}")

Sie sollten etwa Folgendes sehen: Fetched 250 products und den Titel des ersten Produkts.

Schritt 3: Paginierung nutzen, um alle Produkte zu scrapen

Ein einzelner Request liefert maximal 250 Produkte. Die meisten Stores haben mehr (Allbirds hat über 1.420). Sie müssen also durch die Seiten laufen, bis eine leere Antwort zurückkommt.

def scrape_all_products(store_url, delay=1.0):
    """Alle Produkte aus einem Shopify-Store scrapen, inklusive Paginierung."""
    all_products = []
    page = 1
    
    while True:
        print(f"Fetching page {page}...")
        products = fetch_products_page(store_url, page=page, limit=250)
        
        if not products:
            print(f"No more products. Total: {len(all_products)}")
            break
        
        all_products.extend(products)
        print(f"  Got {len(products)} products (total so far: {len(all_products)})")
        page += 1
        
        # Fair bleiben: zwischen den Requests warten
        time.sleep(delay + random.uniform(0, 0.5))
    
    return all_products

Kommt products leer zurück, sind Sie am Ende angekommen.

Das time.sleep() mit zufälligem Jitter hält Sie unter Shopifys informellem Rate Limit von etwa 2 Requests pro Sekunde.

Profi-Tipp: Wer vorher /meta.json abgerufen hat, kennt die Gesamtzahl der Produkte schon und kann exakt berechnen, wie viele Seiten nötig sind: pages = ceil(product_count / 250). So sparen Sie sich den einen unnötigen leeren Request am Ende.

Schritt 4: Die benötigten Felder extrahieren und auswählen

Sobald Sie alle Produkte als Python-Liste von Dictionaries haben, ziehen Sie nur die Felder heraus, die für Sie relevant sind. Hier ein Beispiel fürs Preis-Monitoring mit den wichtigsten Feldern:

def extract_product_data(products):
    """Wichtige Felder aus Produkten extrahieren und Varianten flach darstellen."""
    rows = []
    for product in products:
        for variant in product.get("variants", []):
            rows.append({
                "product_id": product["id"],
                "title": product["title"],
                "handle": product["handle"],
                "vendor": product.get("vendor", ""),
                "product_type": product.get("product_type", ""),
                "tags": ", ".join(product.get("tags", [])),
                "created_at": product.get("created_at", ""),
                "variant_id": variant["id"],
                "variant_title": variant.get("title", ""),
                "sku": variant.get("sku", ""),
                "price": variant.get("price", ""),
                "compare_at_price": variant.get("compare_at_price", ""),
                "available": variant.get("available", ""),
                "image_url": product["images"][0]["src"] if product.get("images") else ""
            })
    return rows

Dadurch entsteht eine Zeile pro Variante – das nützlichste Format für Preisvergleiche, da ein einzelnes Produkt wie „Classic Blue Jeans“ 12 Varianten haben kann (6 Größen × 2 Farben), jede mit eigenem Preis und Verfügbarkeitsstatus.

Shopify-Daten mit pandas als CSV und Excel exportieren

Jeder andere Shopify-Scraping-Leitfaden speichert einfach das rohe JSON und nennt es fertig. Für Entwickler okay. Für Analysten im E-Commerce, die bis Freitag eine Tabelle brauchen, reicht das nicht.

Das Problem: Shopifys JSON ist verschachtelt. Ein Produkt kann ein Dutzend Varianten enthalten, jede mit eigenem Preis, SKU und Verfügbarkeit. Das in Zeilen und Spalten zu bringen, braucht etwas pandas-Arbeit.

Verschachteltes JSON in eine saubere Tabelle überführen

Je nach Ziel gibt es zwei Ansätze:

Option A: Eine Zeile pro Variante (am besten für Preis- und Lagertracking)

# Nutzung der Funktion extract_product_data aus Schritt 4
products = scrape_all_products("https://allbirds.com")
rows = extract_product_data(products)
df = pd.DataFrame(rows)

print(f"DataFrame shape: {df.shape}")
print(df.head())

So erhalten Sie eine flache Tabelle, in der jede Zeile eine eindeutige Produkt-Varianten-Kombination ist. Ein Store mit 500 Produkten und durchschnittlich 4 Varianten pro Produkt ergibt ein DataFrame mit rund 2.000 Zeilen.

Option B: Eine Zeile pro Produktübersicht (am besten für Katalogübersichten)

def summarize_products(products):
    """Eine Zeile pro Produkt mit Minimal- und Maximalpreis über alle Varianten."""
    rows = []
    for product in products:
        prices = [float(v["price"]) for v in product.get("variants", []) if v.get("price")]
        rows.append({
            "product_id": product["id"],
            "title": product["title"],
            "vendor": product.get("vendor", ""),
            "product_type": product.get("product_type", ""),
            "variant_count": len(product.get("variants", [])),
            "min_price": min(prices) if prices else None,
            "max_price": max(prices) if prices else None,
            "any_available": any(v.get("available", False) for v in product.get("variants", [])),
            "tags": ", ".join(product.get("tags", []))
        })
    return rows

Export nach CSV, Excel und Google Sheets

# CSV-Export (utf-8-sig verwenden, damit Excel Sonderzeichen korrekt verarbeitet)
df.to_csv("shopify_products.csv", index=False, encoding="utf-8-sig")

# Excel-Export (openpyxl erforderlich)
df.to_excel("shopify_products.xlsx", index=False, engine="openpyxl")

print("Exported to shopify_products.csv and shopify_products.xlsx")

Für Google Sheets können Sie die Bibliothek gspread mit einem Service Account nutzen, aber ehrlich gesagt: Für die meisten Anwendungsfälle ist der Export nach CSV und das Hochladen zu Google Drive schneller und einfacher.

Produktionsreifes Python-Scraping: Rate Limits, Retries und Anti-Blocking

Das einfache Skript läuft bei kleinen Stores gut. Aber was ist mit Stores mit 5.000+ Produkten oder wenn Sie mehrere Stores direkt hintereinander abfragen? Genau dann fangen die Probleme an.

Shopifys Rate Limits und Blocking-Verhalten verstehen

Shopifys öffentliche JSON-Endpunkte haben keine offiziell dokumentierten Rate Limits wie die Leaky-Bucket-Logik der Admin API, aber empirische Tests zeigen:

  • Sichere Rate: etwa 2 Requests pro Sekunde und Store
  • Weiche Obergrenze: ungefähr 40 Requests pro Minute, bevor Throttling einsetzt
  • HTTP 429: „Too Many Requests“ – die Standardantwort bei Rate Limits
  • HTTP 430: Ein Shopify-spezifischer Code, der auf eine Sicherheitsblockade hinweist, nicht nur auf Rate Limiting
  • HTTP 403 oder CAPTCHA-Weiterleitung: Bei manchen Stores mit zusätzlichem Cloudflare-Schutz

Requests von gemeinsamer Cloud-Infrastruktur (AWS Lambda, Google Cloud Run) lösen besonders häufig Blockaden aus, weil diese IP-Bereiche oft missbraucht werden.

So scrapen Sie Shopify zuverlässig

Hier ist die Entwicklung von „funktioniert auf meinem Laptop“ zu „läuft produktiv“:

StufeTechnikZuverlässigkeit
Basisrequests.get() + ?page=Bricht bei großen Katalogen ab, kann blockiert werden
Mittelrequests.Session() + ?limit=250 + time.sleep(1) + Retry bei 429Funktioniert für die meisten Stores
FortgeschrittenAsync httpx + rotierender User-Agent + exponentielles BackoffProduktionsreif, skaliert auf 10K+ Produkte

Mittleres Niveau (für die meisten Nutzer empfohlen):

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

def create_session():
    """Eine requests-Session mit automatischer Retry-Logik erstellen."""
    session = requests.Session()
    retries = Retry(
        total=5,
        backoff_factor=1,  # sleep: 0.5s, 1s, 2s, 4s, 8s
        status_forcelist=[429, 430, 500, 502, 503, 504],
        respect_retry_after_header=True
    )
    session.mount("https://", HTTPAdapter(max_retries=retries))
    session.headers.update({
        "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"
    })
    return session

Die Retry-Konfiguration behandelt 429-Antworten automatisch mit exponentiellem Backoff. backoff_factor=1 bedeutet, dass die Wartezeiten zwischen den Versuchen 0,5 s → 1 s → 2 s → 4 s → 8 s betragen. Die Wiederverwendung der Session (requests.Session()) sorgt außerdem für Connection Pooling, was den Overhead bei mehreren Requests an dieselbe Domain reduziert.

User-Agent-Rotation: Wenn Sie mehrere Stores scrapen, wechseln Sie zwischen 3–5 realistischen Browser-User-Agents. Das dient nicht der Täuschung – sondern einfach dazu, nicht wie ein Bot zu wirken, der bei jedem Request exakt dieselben Header sendet.

Vollständiges Python-Skript zum Shopify-Scraping mit CSV-Export

Hier ist das komplette Skript zum Kopieren und Einfügen, das alles oben Gesagte zusammenführt. Es umfasst rund 75 echte Codezeilen plus Kommentare und wurde gegen Allbirds (1.420 Produkte), ColourPop (2.000+ Produkte) und Zoologist Perfumes (kleiner Katalog) getestet.

import requests
import pandas as pd
import time
import random
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry


def create_session():
    """Eine Session mit Retry-Logik für Rate Limits erstellen."""
    session = requests.Session()
    retries = Retry(
        total=5,
        backoff_factor=1,
        status_forcelist=[429, 430, 500, 502, 503, 504],
        respect_retry_after_header=True
    )
    session.mount("https://", HTTPAdapter(max_retries=retries))
    session.headers.update({
        "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"
    })
    return session


def scrape_shopify(store_url, delay=1.0):
    """Alle Produkte eines Shopify-Stores über /products.json scrapen."""
    session = create_session()
    all_products = []
    page = 1
    base_url = f"{store_url.rstrip('/')}/products.json"

    while True:
        print(f"  Page {page}...", end=" ")
        resp = session.get(base_url, params={"limit": 250, "page": page}, timeout=30)
        resp.raise_for_status()
        products = resp.json().get("products", [])

        if not products:
            break

        all_products.extend(products)
        print(f"{len(products)} products (total: {len(all_products)})")
        page += 1
        time.sleep(delay + random.uniform(0, 0.5))

    return all_products


def flatten_to_variants(products):
    """Verschachteltes Produkt-JSON in eine Zeile pro Variante überführen."""
    rows = []
    for p in products:
        base = {
            "product_id": p["id"],
            "title": p["title"],
            "handle": p["handle"],
            "vendor": p.get("vendor", ""),
            "product_type": p.get("product_type", ""),
            "tags": ", ".join(p.get("tags", [])),
            "created_at": p.get("created_at", ""),
            "updated_at": p.get("updated_at", ""),
            "image_url": p["images"][0]["src"] if p.get("images") else "",
        }
        for v in p.get("variants", []):
            row = {**base}
            row["variant_id"] = v["id"]
            row["variant_title"] = v.get("title", "")
            row["sku"] = v.get("sku", "")
            row["price"] = v.get("price", "")
            row["compare_at_price"] = v.get("compare_at_price", "")
            row["available"] = v.get("available", "")
            rows.append(row)
    return rows


if __name__ == "__main__":
    STORE_URL = "https://allbirds.com"  # Hier den Ziel-Store eintragen
    OUTPUT_CSV = "shopify_products.csv"
    OUTPUT_EXCEL = "shopify_products.xlsx"

    print(f"Scraping {STORE_URL}...")
    products = scrape_shopify(STORE_URL)
    print(f"\nTotal products scraped: {len(products)}")

    print("Flattening to variant-level rows...")
    rows = flatten_to_variants(products)
    df = pd.DataFrame(rows)
    print(f"DataFrame: {df.shape[0]} rows x {df.shape[1]} columns")

    df.to_csv(OUTPUT_CSV, index=False, encoding="utf-8-sig")
    df.to_excel(OUTPUT_EXCEL, index=False, engine="openpyxl")
    print(f"\nExported to {OUTPUT_CSV} and {OUTPUT_EXCEL}")

Starten Sie es mit python scrape_shopify.py. Bei Allbirds dauert das etwa 45 Sekunden und erzeugt eine CSV mit rund 5.000+ Zeilen, also eine Zeile pro Variante. Die Terminalausgabe sieht ungefähr so aus:

Scraping https://allbirds.com...
  Page 1... 250 products (total: 250)
  Page 2... 250 products (total: 500)
  ...
  Page 6... 170 products (total: 1420)

Total products scraped: 1420
Flattening to variant-level rows...
DataFrame: 5680 rows x 14 columns

Exported to shopify_products.csv and shopify_products.xlsx

Ohne Python: Shopify in 2 Klicks mit Thunderbit scrapen (No-Code-Alternative)

Nicht jeder möchte Python installieren, Importfehler beheben oder ein Scraping-Skript pflegen. Für den Vertriebsmitarbeiter, der morgen früh Konkurrenzpreise braucht, ist Python einfach zu viel.

Genau deshalb haben wir die Thunderbit Official Website entwickelt – einen KI-Webscraper als Chrome-Erweiterung. Kein Code, keine API-Keys, kein Setup der Entwicklungsumgebung.

Thunderbit-Chrome-Erweiterung testen

So scrapt Thunderbit Shopify-Stores

Thunderbit hat eine speziell konfigurierte Shopify Scraper-Vorlage, die für Shopify-Produktseiten vorbereitet ist. Sie installieren die Thunderbit Chrome Extension Download Page, öffnen einen Shopify-Store und klicken auf „Scrape“. Die Vorlage extrahiert automatisch Produktnamen, Beschreibungen, Preise, Variantendetails, Bilder und Anbieterinformationen.

Bei Stores, die nicht ganz zum Template passen (etwa bei benutzerdefinierten Themes oder ungewöhnlichen Layouts), liest Thunderbits Funktion AI Suggest Fields die Seite aus und schlägt automatisch Spaltennamen vor. Diese passen Sie an – Spalten umbenennen, Felder hinzufügen oder Anweisungen wie „nur Produkte mit gesetztem compare_at_price extrahieren“ geben.

Einige Funktionen, die direkt dem entsprechen, was das Python-Skript erledigt:

  • Subpage-Scraping: Ruft automatisch jede Produktdetailseite auf und reichert die Tabelle mit vollständigen Beschreibungen, Rezensionen oder Variantendetails an – genau wie unser Python-Skript durch das Durchlaufen der Seiten, nur eben ohne Code.
  • Automatische Paginierung: Verarbeitet Klick-Paginierung und unendliches Scrollen ohne Konfiguration.
  • Geplantes Scraping: Richten Sie wiederkehrende Jobs ein (zum Beispiel „jeden Montag um 9 Uhr“) für laufendes Preis-Monitoring – ganz ohne Cronjob oder Server.
  • Kostenloser Export nach CSV, Excel, Google Sheets, Airtable oder Notion in allen Plänen.

Python-Skript vs. Thunderbit: Ehrlicher Vergleich

FaktorPython-SkriptThunderbit (No-Code)
Einrichtungszeit15–60 Min. (Umgebung + Code)ca. 2 Min. (Chrome-Erweiterung installieren)
Programmieren erforderlichJa (Python)Nein
AnpassbarkeitUnbegrenztKI-vorgeschlagene Felder + eigene Prompts
PaginierungMuss manuell programmiert werdenAutomatisch
ExportformateSelbst programmieren (CSV/Excel)CSV, Excel, Google Sheets, Airtable, Notion (kostenlos)
Geplante LäufeCronjob + HostingIntegrierter Scheduler
Umgang mit Rate LimitsRetries/Backoff selbst bauenWird automatisch behandelt
Am besten geeignet fürEntwickler, große DatenpipelinesBusiness-Anwender, schnelle Exporte, regelmäßiges Monitoring

Nutzen Sie Python, wenn Sie volle Kontrolle brauchen oder das Ganze in eine größere Datenpipeline integrieren möchten. Nutzen Sie Thunderbit, wenn Sie Daten schnell brauchen und keinen Code pflegen möchten. Einen tieferen Einblick in Web Scraping für Preisvergleiche finden Sie in unserem separaten Leitfaden zu diesem Thema.

python-vs-thunderbit-comparison.webp

Tipps und Best Practices für das Scraping von Shopify-Stores

Diese gelten unabhängig vom Tool, das Sie verwenden:

  • Immer ?limit=250 verwenden, um die Anzahl der Requests zu minimieren. Der Standardwert von 30 pro Seite bedeutet 8x mehr Requests für dieselben Daten.
  • Den Store respektieren: Legen Sie zwischen den Requests 1–2 Sekunden Pause ein. Einen Server mit sehr vielen schnellen Anfragen zu belasten ist schlechte Praxis und erhöht die Blockierwahrscheinlichkeit.
  • Zuerst robots.txt prüfen: Shopifys Standard-robots.txt blockiert /products.json nicht. Manche Stores setzen aber eigene Regeln, daher vor großem Scraping kurz prüfen.
  • Rohes JSON zuerst lokal speichern, dann verarbeiten. Wenn sich Ihre Parsing-Logik später ändert, müssen Sie nicht noch einmal scrapen. Ein einfaches json.dump(all_products, open("raw_data.json", "w")) vor dem Flattening spart viel Ärger.
  • Nach product.id deduplizieren: In Randfällen der Paginierung können an Seitenübergängen doppelte Produkte auftauchen. Ein schnelles df.drop_duplicates(subset=["product_id", "variant_id"]) behebt das.
  • price vor Berechnungen in Float umwandeln. Shopify liefert Preise als Strings ("185.00"), nicht als Zahlen.
  • Auf Änderungen am Endpunkt achten: Auch wenn /products.json seit Jahren stabil ist, könnte Shopify ihn theoretisch einschränken. Wenn Ihr Scraper plötzlich 404 zurückgibt, prüfen Sie zuerst den Store manuell.

Für mehr zu robusten Scrapern lesen Sie unseren Leitfaden zu Best Practices für Web-Scraping-Tools.

Rechtliche und ethische Aspekte beim Scraping von Shopify

Kurz, aber wichtig.

Der /products.json-Endpunkt liefert öffentlich verfügbare Produktdaten – also genau die Informationen, die jeder Besucher beim Stöbern im Store sieht. In Shopifys Nutzungsbedingungen gibt es Formulierungen, die die Nutzung „automatisierter Mittel“ für den Zugriff auf „die Dienste“ untersagen, aber damit ist die Plattform selbst gemeint (Admin-Dashboard, Checkout), nicht die öffentlichen Storefront-Daten. Bis April 2026 wurden keine Shopify-spezifischen Scraping-Klagen eingereicht.

Wichtige Präzedenzfälle stützen das Scraping öffentlicher Daten: Der Fall hiQ v. LinkedIn stellte klar, dass das Scrapen öffentlich zugänglicher Daten keinen Verstoß gegen den CFAA darstellt, und Meta v. Bright Data (2024) entschied, dass TOS-Beschränkungen nur gelten, wenn ein Nutzer eingeloggt ist.

Best Practices:

  • Nur öffentlich zugängliche Produktdaten scrapen
  • Keine persönlichen oder Kundendaten scrapen
  • robots.txt und Rate Limits respektieren
  • DSGVO/CCPA einhalten, falls personenbezogene Daten verarbeitet werden (Produktkatalogdaten sind nicht personenbezogen)
  • Sich mit einem klaren User-Agent-String identifizieren
  • Den eigenen Shopify-Store über die Admin API zu scrapen ist immer unproblematisch

Für einen tieferen Einblick lesen Sie unseren Beitrag zu den rechtlichen Implikationen von Web Scraping.

Fazit und wichtigste Erkenntnisse

Shopifys öffentlicher /products.json-Endpunkt macht die Extraktion von E-Commerce-Daten so einfach wie kaum etwas anderes. Der Ablauf lautet: /products.json anhängen → mit Python abrufen → mit ?limit=250&page= paginieren → mit pandas flatten → als CSV oder Excel exportieren.

Was dieser Leitfaden im Vergleich zu anderen zusätzlich bietet:

  • Vollständige Feldreferenz: Wissen Sie vor der ersten Codezeile genau, welche Daten verfügbar sind (40+ Felder über Produkte, Varianten und Bilder)
  • Zusätzliche Endpunkte: /collections.json und /meta.json liefern Kategorien-Insights und Store-Metadaten, die in anderen Tutorials fehlen
  • Produktionsreife Techniken: Session-Wiederverwendung, exponentielles Backoff, User-Agent-Header und ?limit=250 für reale Rate-Limit-Situationen
  • Sauberer CSV-/Excel-Export: Mit pandas aufgelöste Variantendaten statt bloßer JSON-Dumps
  • No-Code-Alternative: Thunderbit für alle, die Geschwindigkeit über Code-Flexibilität stellen

Für einmalige oder regelmäßige Shopify-Datenabzüge ohne Code probieren Sie die Thunderbit Chrome Extension Download Page – die Shopify Scraper-Vorlage übernimmt alles von der Paginierung bis zum Export. Für individuelle Datenpipelines oder Scraping im großen Stil über viele Stores hinweg bietet Ihnen das Python-Skript in diesem Leitfaden volle Kontrolle.

Schauen Sie sich unseren Thunderbit YouTube-Kanal für Video-Anleitungen an oder entdecken Sie unsere Leitfäden zu Amazon-Produkten scrapen und Daten von Websites nach Excel extrahieren für verwandte Techniken.

Thunderbit für Shopify-Scraping testen Get Started Free

FAQs

Kann man jeden Shopify-Store mit products.json scrapen?

Die meisten Shopify-Stores stellen diesen Endpunkt standardmäßig bereit – in Tests lieferten etwa 71 % gültiges JSON. Einige Stores mit individuellen Konfigurationen oder zusätzlichen Sicherheitsschichten (Cloudflare, Headless-Setups) geben möglicherweise 404 zurück oder blockieren die Anfrage. Der Schnellcheck: Öffnen Sie {store-url}/products.json im Browser. Wenn Sie JSON sehen, passt es.

Ist es legal, Shopify-Stores zu scrapen?

Öffentliche Produktdaten (Preise, Titel, Bilder, Beschreibungen) sind grundsätzlich zugänglich, und Präzedenzfälle wie hiQ v. LinkedIn stützen das Scraping öffentlich verfügbarer Informationen. Prüfen Sie dennoch immer die Nutzungsbedingungen des jeweiligen Stores und die Gesetze Ihres Landes. Scrapen Sie keine personenbezogenen oder Kundendaten und respektieren Sie Rate Limits.

Wie viele Produkte kann man aus einem Shopify-Store scrapen?

Es gibt keine feste Obergrenze für die Gesamtzahl. Mit der Paginierung über ?limit=250&page= rufen Sie den gesamten Katalog ab. Bei sehr großen Stores (25.000+ Produkte) sollten Sie Session-Wiederverwendung und Pausen nutzen, um Rate Limits zu vermeiden. Der /meta.json-Endpunkt zeigt Ihnen vorab die genaue Produktanzahl, sodass Sie wissen, wie viele Seiten zu erwarten sind.

Was ist der Unterschied zwischen products.json und der Shopify Admin API?

/products.json ist ein öffentlicher Endpunkt – keine Authentifizierung, nur lesbare Produktdaten, für jeden zugänglich. Die Admin API benötigt Zugriffstoken des Store-Besitzers und liefert Bestellungen, Bestandsmengen, Kundendaten und Schreibzugriff. Wenn Sie Verkaufsdaten oder echte Lagerbestände brauchen, benötigen Sie Admin-API-Zugriff, also die Berechtigung des Store-Besitzers.

Kann ich Shopify auch ohne Python scrapen?

Absolut. Tools wie Thunderbit Official Website ermöglichen es, Shopify-Stores direkt über eine Chrome-Erweiterung ohne Code zu scrapen. Die Paginierung wird automatisch verarbeitet und der Export erfolgt direkt nach CSV, Excel, Google Sheets, Airtable oder Notion. Für Entwickler, die andere Sprachen bevorzugen, funktioniert derselbe /products.json-Endpunkt auch mit JavaScript, Ruby, Go – also jeder Sprache, die HTTP-Requests senden und JSON parsen kann.

Mehr erfahren

Ke
Ke
CTO bei Thunderbit | Senior Data Scientist & ML-Experte Mit fast zehn Jahren Erfahrung in Machine Learning und Data Science ist Ke Shen Absolvent der Columbia University und ehemaliger Senior Data Scientist bei Walmart Labs. Mit tiefgreifender, von Fachkollegen anerkannter Expertise in Python, R, Java und Statistik teilt er praxiserprobte Einblicke dazu, wie sich komplexe KI-Algorithmen von der Theorie in eine produktionsreife Architektur überführen lassen.

Thunderbit ausprobieren

Leads und andere Daten in nur 2 Klicks extrahieren. Mit KI unterstützt.

Thunderbit holen Es ist kostenlos
Daten mit KI extrahieren
Daten einfach zu Google Sheets, Airtable oder Notion übertragen
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week