L’endpoint /products.json di Shopify è uno di quei segreti di Pulcinella che, nel mondo dei dati ecommerce, valgono oro. Ti basta aggiungerlo all’URL di qualunque negozio Shopify per ricevere in risposta JSON già strutturato: niente chiavi API, niente autenticazione, niente scraping di HTML complicato e tutto annidato.
Io lavoro nel team del , quindi passo parecchio tempo a ragionare su come le persone estraggono dati dal web. E lo scraping di Shopify salta fuori continuamente: team sales che tengono d’occhio i prezzi dei concorrenti, operatori ecommerce che confrontano i cataloghi prodotti, addetti agli acquisti che cercano nuovi fornitori. Con su Shopify e una quota di circa , la quantità di dati prodotto che puoi estrarre è enorme.
Questa guida copre tutto il flusso: cosa restituisce l’endpoint, come fare la paginazione su migliaia di prodotti, come gestire i limiti di richiesta senza farsi bloccare e come appiattire il JSON annidato di Shopify in un CSV o file Excel pulito usando pandas. Vedremo anche gli endpoint che quasi nessuno cita (/collections.json, /meta.json) e un’alternativa no-code per chi preferisce evitare Python del tutto.
Che cos’è l’endpoint /products.json di Shopify (e perché rende lo scraping così semplice)
Ogni negozio Shopify ha un endpoint pubblico su {store-url}/products.json che restituisce dati prodotto già strutturati. Nessuna chiave API. Nessun OAuth. Nessuna autenticazione di alcun tipo. Ti basta aggiungere /products.json all’URL dello store per ottenere un array JSON con tutti i prodotti del catalogo.
Provalo subito: apri oppure nel browser. Vedrai un JSON pulito e ben organizzato con titoli dei prodotti, prezzi, varianti, immagini, tag: tutto al posto giusto.
Confrontalo con l’alternativa: analizzare i temi HTML di Shopify, che sono profondamente annidati, incoerenti da uno store all’altro e cambiano ogni volta che il merchant aggiorna il tema. Ecco la differenza:
Approccio HTML (scomodo):
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>
Approccio JSON (pulito):
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}
Il JSON vince per coerenza, affidabilità e facilità di parsing. L’endpoint supporta anche due parametri di query fondamentali—?limit= (fino a 250 prodotti per pagina, con default 30) e ?page= per la paginazione—che useremo spesso nel codice qui sotto.
Distinzione importante: questo è un endpoint pubblico della vetrina, non la . L’Admin API richiede token di accesso del proprietario dello store e fornisce dati su ordini, livelli di inventario e informazioni sui clienti. L’endpoint pubblico /products.json espone solo dati prodotto in sola lettura, accessibili a chiunque. Più avanti chiarirò bene la differenza, perché nei forum si fa confusione di continuo.
Una precisazione: non tutti i negozi Shopify espongono questo endpoint. Nei miei test, circa il 71% degli store restituisce JSON valido (allbirds.com, gymshark.com, colourpop.com, kyliecosmetics.com funzionano tutti), mentre alcune configurazioni personalizzate restituiscono un 404 (hiutdenim.co.uk, bombas.com). Il controllo rapido è semplice: visita {store-url}/products.json nel browser e guarda cosa succede.
Perché estrarre dati da Shopify con Python? I principali casi d’uso business
Perché farlo? Per il ROI. usa ormai lo scraping automatico dei prezzi per l’intelligence competitiva, contro appena il 34% nel 2020. E le ricerche mostrano che un . I dati, insomma, valgono soldi veri.
Ecco i casi d’uso più comuni che vedo:
| Caso d’uso | Chi ne beneficia | Cosa ottieni |
|---|---|---|
| Monitoraggio prezzi dei concorrenti | Team operations ecommerce | Tracciamento di variazioni di prezzo, sconti e prezzi di confronto nei cataloghi concorrenti |
| Ricerca prodotto e sourcing | Procurement / merchandising | Confronto di caratteristiche prodotto, varianti, materiali e disponibilità |
| Lead generation | Team sales | Estrazione di nomi fornitori, dati brand e informazioni di contatto dai cataloghi |
| Analisi di mercato e di categoria | Team marketing | Comprensione di mix prodotti, tag, struttura delle collection e posizionamento |
| Tracciamento inventario e disponibilità | Team supply chain | Monitoraggio nel tempo dello stato di stock a livello di variante (available: true/false) |
| Rilevamento nuovi prodotti | Team prodotto | Tracciamento dei timestamp created_at per individuare i nuovi lanci dei concorrenti |
Python è la scelta naturale per questo tipo di lavoro. usa Python come linguaggio principale, e l’ecosistema—requests per HTTP, pandas per la manipolazione dei dati, httpx per l’asincrono—rende facile passare da “ho un URL” a “ho un foglio di calcolo” in meno di 80 righe di codice.
Riferimento completo dei campi di products.json: spiegazione di ogni campo
Ogni tutorial concorrente ti mostra title, id e handle, poi passa oltre. La risposta JSON di Shopify contiene oltre 40 campi tra prodotti, varianti, immagini e opzioni. Sapere cosa è disponibile prima di scrivere il codice di scraping ti evita di dover rifare tutto dopo.
Questa reference è stata ricavata da risposte live di /products.json ottenute il 16 aprile 2026. La struttura è coerente in tutti gli store che espongono l’endpoint.
Campi a livello prodotto
| Campo | Tipo di dato | Valore di esempio | Caso d’uso business |
|---|---|---|---|
id | Integer | 123456789 | Identificatore univoco del prodotto per la deduplicazione |
title | String | "Classic Blue Jeans" | Nome prodotto per cataloghi e confronti |
handle | String | "classic-blue-jeans" | Slug URL—costruisci i link alle pagine prodotto come {store}/products/{handle} |
body_html | String (HTML) or null | Our best-selling... | Descrizione prodotto per analisi contenuti e SEO |
vendor | String | "Hiut Denim" | Nome brand/fornitore per lead gen o sourcing |
product_type | String | "Jeans" | Classificazione di categoria per analisi di mercato |
created_at | ISO DateTime | "2024-01-15T10:30:00-05:00" | Traccia quando i prodotti sono stati aggiunti (rilevamento nuovi lanci) |
updated_at | ISO DateTime | "2025-03-01T08:00:00-05:00" | Individua modifiche recenti al catalogo |
published_at | ISO DateTime | "2024-01-16T00:00:00-05:00" | Indica quando i prodotti sono diventati visibili sullo store |
tags | Array of Strings | ["organic", "women", "straight-leg"] | Analisi di keyword/tag per SEO, categorizzazione e trend spotting |
variants | Array of Objects | (see variant fields below) | Prezzo, SKU e disponibilità per variante |
images | Array of Objects | (see image fields below) | URL delle immagini prodotto per cataloghi e analisi visiva |
options | Array of Objects | [{"name": "Size", "values": ["S","M","L"]}] | Comprensione della configurazione del prodotto (taglia, colore, materiale) |
Campi a livello variante (annidati sotto ogni prodotto)
| Campo | Tipo di dato | Esempio | Caso d’uso |
|---|---|---|---|
id | Integer | 987654321 | Identificatore univoco della variante |
title | String | "32 / Blue" | Nome visualizzato della variante |
sku | String | "HD-BLU-32" | Confronto SKU per i sistemi di inventario |
price | String | "185.00" | Monitoraggio prezzi (nota: è una stringa, va convertita in float per i calcoli) |
compare_at_price | String or null | "200.00" | Prezzo originale—fondamentale per tracciare gli sconti |
available | Boolean | true | Disponibilità stock (l’unico indicatore pubblico disponibile) |
weight | Float | 1.2 | Analisi logistica e di spedizione |
option1, option2, option3 | String | "32", "Blue", null | Valori delle singole opzioni |
created_at, updated_at | ISO DateTime | — | Tracciamento delle modifiche a livello variante |
Campi a livello immagine
| Campo | Tipo di dato | Esempio | Caso d’uso |
|---|---|---|---|
id | Integer | 111222333 | Identificatore univoco dell’immagine |
src | String (URL) | "https://cdn.shopify.com/..." | Link diretto per scaricare l’immagine |
alt | String or null | "Front view of jeans" | Testo alt dell’immagine per analisi accessibilità |
position | Integer | 1 | Ordinamento delle immagini |
width, height | Integer | 2048, 2048 | Dimensioni dell’immagine |
Cosa NON è presente nell’endpoint pubblico
Un dettaglio importante: inventory_quantity NON è disponibile nelle risposte pubbliche di /products.json. Questo campo è stato rimosso dagli endpoint JSON pubblici nel dicembre 2017 per motivi di sicurezza. L’unico indicatore di stock che ottieni è il campo booleano available di ogni variante (true o false). Per accedere ai conteggi reali dell’inventario serve l’Admin API autenticata con le credenziali del proprietario dello store.
Prima di scrivere il codice di scraping, analizza questa tabella e decidi quali campi servono davvero al tuo caso d’uso. Se fai monitoraggio prezzi, ti servono variants[].price, variants[].compare_at_price e variants[].available. Se fai lead generation, concentrati su vendor, product_type e tags. Filtra di conseguenza: il CSV sarà molto più pulito.
Oltre products.json: collections, meta e altri endpoint Shopify
Nessun tutorial concorrente menziona questi endpoint. Eppure sono fondamentali per un lavoro serio di competitive intelligence.
/collections.json — Tutte le categorie dello store
Restituisce tutte le collection (categorie) del negozio con titoli, handle, descrizioni e numero di prodotti. Ho verificato questo comportamento su zoologistperfumes.com, allbirds.com e gymshark.com: tutti hanno restituito JSON valido.
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}
Vuoi capire come un concorrente organizza il proprio catalogo? Questo è l’endpoint giusto.
/collections/{handle}/products.json — Prodotti per categoria
Restituisce i prodotti filtrati per una collection specifica. La struttura JSON è la stessa di /products.json, ma limitata a una sola categoria. È fondamentale per lo scraping a livello di categoria—per esempio se vuoi monitorare solo la collection “Sale” o “New Arrivals” di un concorrente.
/meta.json — Metadati dello store
Restituisce nome store, descrizione, valuta, paese e—ecco la parte interessante—published_products_count. Questo conteggio ti permette di calcolare in anticipo quante pagine di paginazione ti serviranno: ceil(published_products_count / 250). Niente più tentativi a caso finché non arriva una risposta vuota.
Quale endpoint dovresti usare?
| Cosa vuoi ottenere | Endpoint | Serve autenticazione? |
|---|---|---|
| Tutti i prodotti (pubblici) | /products.json | No |
| Prodotti in una categoria specifica | /collections/{handle}/products.json | No |
| Metadati store + numero prodotti | /meta.json | No |
| Tutte le collection (categorie) | /collections.json | No |
| Dati ordini/vendite (solo il tuo store) | Admin API /orders.json | Sì (API key) |
| Quantità inventario (solo il tuo store) | Admin API /inventory_levels.json | Sì |
La domanda che torna sempre nei forum—“Posso estrarre quanti pezzi ha venduto un concorrente?”—ha una risposta breve: no. Non dagli endpoint pubblici. I dati di vendita e le quantità di inventario richiedono l’Admin API autenticata, quindi serve l’accesso del proprietario dello store. Gli endpoint pubblici forniscono solo dati del catalogo prodotti.

Come estrarre dati da Shopify con Python: configurazione passo dopo passo
- Difficoltà: Principiante
- Tempo richiesto: ~15 minuti (setup + prima estrazione)
- Cosa ti serve: Python 3.11+,
pip, un terminale e l’URL di uno store Shopify da estrarre
Passo 1: Installa Python e le librerie necessarie
Assicurati di avere installato Python 3.11 o una versione più recente (pandas 3.0.x lo richiede). Poi installa le due librerie che ci servono:
1pip install requests pandas
Per esportare in Excel, ti servirà anche:
1pip install openpyxl
All’inizio dello script, aggiungi questi import:
1import requests
2import pandas as pd
3import time
4import random
5import json
Quando esegui lo script, non dovresti vedere errori di importazione. Se pandas restituisce un errore di versione, aggiorna Python alla 12.
Passo 2: Recupera i dati prodotto da /products.json
Ecco una funzione base che prende l’URL dello store, chiama l’endpoint e restituisce il JSON parsato:
1def fetch_products_page(store_url, page=1, limit=250):
2 """Recupera una singola pagina di prodotti da uno store Shopify."""
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", [])
Dettagli importanti:
limit=250è il massimo consentito da Shopify per pagina. Il default è 30, quindi impostarlo esplicitamente riduce fino a 8 volte il numero totale di richieste.- Header
User-Agent: impostane sempre uno realistico. Le richieste senza User-Agent hanno più probabilità di attivare i sistemi anti-bot di Shopify. timeout=30: non lasciare che una singola richiesta resti bloccata per sempre.
Testalo con uno store noto:
1products = fetch_products_page("https://allbirds.com")
2print(f"Fetched {len(products)} products")
3print(f"First product: {products[0]['title']}")
Dovresti vedere qualcosa come: Fetched 250 products e il titolo del primo prodotto.
Passo 3: Gestisci la paginazione per estrarre tutti i prodotti
Una singola richiesta restituisce al massimo 250 prodotti. Molti store ne hanno molti di più (Allbirds ne ha oltre 1.420). Devi ciclare sulle pagine finché non ottieni una risposta vuota.
1def scrape_all_products(store_url, delay=1.0):
2 """Estrae tutti i prodotti da uno store Shopify gestendo la paginazione."""
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 # Comportati bene: attendi tra una richiesta e l’altra
15 time.sleep(delay + random.uniform(0, 0.5))
16 return all_products
Quando products torna vuoto, sei arrivato alla fine.
Il time.sleep() con un po’ di jitter casuale ti tiene sotto il limite di richiesta informale di Shopify (~2 richieste/secondo).
Consiglio utile: se hai prima interrogato /meta.json, conosci già il numero totale di prodotti e puoi calcolare esattamente quante pagine servono: pages = ceil(product_count / 250). Così eviti il classico “una richiesta vuota in più alla fine”.
Passo 4: Analizza e seleziona i campi che ti servono
Ora che hai tutti i prodotti come lista Python di dizionari, estrai solo i campi che ti interessano. Ecco un esempio che prende i campi più comuni per il monitoraggio prezzi:
1def extract_product_data(products):
2 """Estrae i campi chiave dai prodotti, appiattendo le varianti."""
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
Questo crea una riga per variante: il formato più utile per confrontare i prezzi, perché un singolo prodotto come “Classic Blue Jeans” potrebbe avere 12 varianti (6 taglie × 2 colori), ciascuna con il proprio prezzo e stato di disponibilità.
Esportare i dati Shopify estratti in CSV ed Excel con pandas
Ogni altro tutorial sullo scraping di Shopify si limita a scaricare il JSON grezzo in un file e dire che il lavoro è fatto. Va bene per gli sviluppatori. Molto meno utile per l’analista ecommerce che entro venerdì ha bisogno di un foglio di calcolo.
Il problema è semplice: il JSON di Shopify è annidato. Un prodotto può contenere una dozzina di varianti, ognuna con prezzo, SKU e disponibilità propri. Appiattire tutto in righe e colonne richiede un po’ di lavoro con pandas.
Appiattire il JSON annidato in una tabella pulita
Ci sono due approcci, a seconda del caso d’uso:
Opzione A: una riga per variante (la migliore per monitoraggio prezzi e inventario)
1# Usando la funzione extract_product_data del Passo 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())
Otterrai una tabella piatta in cui ogni riga è una combinazione unica prodotto-variante. Uno store con 500 prodotti e una media di 4 varianti per prodotto produce un DataFrame di circa 2.000 righe.
Opzione B: una riga per riepilogo prodotto (la migliore per una panoramica del catalogo)
1def summarize_products(products):
2 """Una riga per prodotto con prezzo minimo/massimo tra le varianti."""
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
Esporta in CSV, Excel e Google Sheets
1# Export CSV (usa utf-8-sig così Excel gestisce bene i caratteri speciali)
2df.to_csv("shopify_products.csv", index=False, encoding="utf-8-sig")
3# Export Excel (richiede openpyxl)
4df.to_excel("shopify_products.xlsx", index=False, engine="openpyxl")
5print("Exported to shopify_products.csv and shopify_products.xlsx")
Per Google Sheets puoi usare la libreria gspread con un service account, ma onestamente—per la maggior parte dei casi—esportare in CSV e poi caricare tutto su Google Drive è più rapido e semplice.
Scraping Python pronto per la produzione: rate limit, retry e anti-blocking
Lo script base va benissimo per gli store piccoli. Ma devi estrarre uno store con oltre 5.000 prodotti, o più store in sequenza? È lì che iniziano i problemi.
Capire i rate limit e il comportamento di blocco di Shopify
Gli endpoint JSON pubblici di Shopify non hanno limiti di rate formalmente documentati (a differenza del modello a bucket dell’Admin API), ma i test sul campo mostrano:
- Tasso sicuro: circa 2 richieste al secondo per store
- Soglia morbida: circa 40 richieste al minuto prima che parta il throttling
- HTTP 429: “Too Many Requests” — la classica risposta da rate limit
- HTTP 430: codice specifico di Shopify che indica un blocco di sicurezza, non solo rate limiting
- HTTP 403 o redirect a CAPTCHA: alcuni store con protezioni Cloudflare aggiuntive
Le richieste provenienti da infrastrutture cloud condivise (AWS Lambda, Google Cloud Run) hanno una probabilità più alta di essere bloccate, perché quegli intervalli IP hanno tassi di abuso più elevati.
Tecniche per estrarre Shopify in modo affidabile
Ecco il percorso da “funziona sul mio portatile” a “gira in produzione”:
| Livello | Tecnica | Affidabilità |
|---|---|---|
| Base | requests.get() + ?page= | Si rompe con cataloghi grandi, può essere bloccato |
| Intermedio | requests.Session() + ?limit=250 + time.sleep(1) + retry su 429 | Funziona per la maggior parte degli store |
| Avanzato | httpx asincrono + rotazione User-Agent + backoff esponenziale | Pronto per produzione, scala a oltre 10K prodotti |
Livello intermedio (consigliato per la maggior parte degli utenti):
1import requests
2from requests.adapters import HTTPAdapter
3from urllib3.util.retry import Retry
4def create_session():
5 """Crea una sessione requests con logica di retry automatica."""
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
La configurazione Retry gestisce automaticamente le risposte 429 con backoff esponenziale. Il backoff_factor=1 significa che il tempo di attesa tra i tentativi è 0,5s → 1s → 2s → 4s → 8s. Il riutilizzo della sessione (requests.Session()) offre anche connection pooling, riducendo l’overhead quando fai più richieste allo stesso dominio.
Rotazione dello User-Agent: se estrai dati da più store, alterna 3–5 stringhe User-Agent realistiche da browser. Non si tratta di “ingannare” qualcuno: serve a non sembrare un bot che invia sempre gli stessi header a ogni richiesta.
Script Python completo e funzionante per estrarre Shopify con export CSV
Ecco lo script completo, pronto da copiare e incollare, che combina tutto quanto sopra. È lungo circa 75 righe di codice reale (più i commenti) e l’ho testato su Allbirds (1.420 prodotti), ColourPop (oltre 2.000 prodotti) e Zoologist Perfumes (catalogo piccolo).
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 """Crea una sessione con logica di retry per i rate limit."""
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 """Estrae tutti i prodotti da uno store Shopify tramite /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 """Appiattisce il JSON annidato dei prodotti in una riga per variante."""
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" # Cambia questo con lo store target
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}")
Eseguilo con python scrape_shopify.py. Per Allbirds, questo richiede circa 45 secondi e produce un CSV con oltre 5.000 righe circa (una per variante). L’output nel terminale sarà simile a questo:
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
Salta Python: estrai dati da Shopify in 2 clic con Thunderbit (alternativa no-code)
Non tutti vogliono installare Python, risolvere errori di import o mantenere uno script di scraping. Per il commerciale che ha bisogno dei prezzi dei concorrenti già domani mattina, Python è probabilmente troppo.
Per questo abbiamo creato —un AI web scraper che funziona come estensione Chrome. Nessun codice, nessuna chiave API, nessuna configurazione dell’ambiente.
Come Thunderbit estrae i dati dagli store Shopify
Thunderbit ha un template dedicato per Shopify Scraper già configurato per le pagine prodotto Shopify. Installi la , vai su uno store Shopify e clicchi su “Scrape”. Il template estrae automaticamente nomi prodotto, descrizioni, prezzi, dettagli delle varianti, immagini e informazioni sul vendor.
Per gli store in cui il template non combacia alla perfezione (temi personalizzati, layout insoliti), la funzione AI Suggest Fields di Thunderbit legge la pagina e genera automaticamente i nomi delle colonne. Puoi personalizzarli: rinominare colonne, aggiungere campi, scrivere istruzioni come “estrae solo i prodotti con compare_at_price valorizzato”.
Alcune funzionalità corrispondono direttamente a ciò che fa lo script Python:
- Scraping delle sottopagine: visita automaticamente ogni pagina dettaglio prodotto e arricchisce la tabella con descrizioni complete, recensioni o dettagli di variante—la stessa cosa che fa il nostro script Python iterando sulle pagine, ma senza codice.
- Paginazione automatica: gestisce paginazione con click e infinite scroll senza configurazioni.
- Scraping pianificato: imposta job ricorrenti (per esempio “ogni lunedì alle 9:00”) per il monitoraggio prezzi continuo—senza cron job o server.
- Export gratuito in CSV, Excel, Google Sheets, Airtable o Notion su tutti i piani.
Script Python vs. Thunderbit: confronto onesto
| Fattore | Script Python | Thunderbit (No-Code) |
|---|---|---|
| Tempo di configurazione | 15–60 min (ambiente + codice) | ~2 min (installazione estensione Chrome) |
| Codice richiesto | Sì (Python) | Nessuno |
| Personalizzazione | Illimitata | Campi suggeriti dall’AI + prompt personalizzati |
| Gestione paginazione | Va programmata manualmente | Automatica |
| Formati di export | Da programmare da soli (CSV/Excel) | CSV, Excel, Google Sheets, Airtable, Notion (gratis) |
| Esecuzioni pianificate | Cron job + hosting | Scheduler integrato |
| Gestione rate limit | Devi programmare retry/backoff | Gestita automaticamente |
| Ideale per | Sviluppatori, pipeline dati su larga scala | Utenti business, estrazioni rapide, monitoraggio ricorrente |
Usa Python quando ti serve pieno controllo o devi integrarlo in una pipeline dati più ampia. Usa Thunderbit quando ti servono dati subito e non vuoi mantenere codice. Per un approfondimento su , abbiamo scritto una guida dedicata su quel tema.

Consigli e best practice per estrarre dati dagli store Shopify
Questi valgono indipendentemente dallo strumento che scegli:
- Usa sempre
?limit=250per ridurre al minimo il numero totale di richieste. Il default di 30 per pagina significa 8 volte più richieste per gli stessi dati. - Rispetta lo store: inserisci pause di 1–2 secondi tra le richieste. Martellare un server con richieste a raffica è una cattiva pratica e aumenta le probabilità di essere bloccato.
- Controlla prima
robots.txt: ilrobots.txtstandard di Shopify NON blocca/products.json. Però alcuni store aggiungono regole personalizzate, quindi verifica prima di estrarre su larga scala. - Salva prima il JSON grezzo in locale, poi processalo. Se in seguito cambia la logica di parsing, non dovrai rifare lo scraping. Un semplice
json.dump(all_products, open("raw_data.json", "w"))prima dell’appiattimento ti risparmia problemi. - Deduplica per
product.id: in alcuni casi le pagine di confine della paginazione possono restituire prodotti duplicati. Un rapidodf.drop_duplicates(subset=["product_id", "variant_id"])risolve il problema. - Converti
pricein float prima di fare calcoli. Shopify restituisce i prezzi come stringhe ("185.00"), non come numeri. - Monitora eventuali cambiamenti dell’endpoint: anche se
/products.jsonè stabile da anni, Shopify potrebbe teoricamente limitarlo. Se il tuo scraper improvvisamente restituisce 404, controlla prima manualmente lo store.
Per approfondire come costruire scraper robusti, leggi la nostra guida su .
Considerazioni legali ed etiche quando si estraggono dati da Shopify
Sezione breve, ma importante.
L’endpoint /products.json espone dati prodotto pubblicamente disponibili—le stesse informazioni che qualsiasi visitatore vede navigando nello store. I Termini di servizio di Shopify includono una formula che vieta l’uso di “mezzi automatizzati” per accedere ai “Servizi”, ma questa formulazione si riferisce alla piattaforma in sé (dashboard admin, checkout), non ai dati pubblici della vetrina. Ad aprile 2026 non risultano cause legali specifiche contro lo scraping di Shopify.
I precedenti legali più rilevanti supportano lo scraping di dati pubblici: il caso hiQ v. LinkedIn ha stabilito che lo scraping di dati pubblicamente accessibili non viola il CFAA, e Meta v. Bright Data (2024) ha stabilito che le restrizioni nei TOS si applicano solo quando l’utente è autenticato.
Best practice:
- Estrai solo dati prodotto pubblicamente disponibili
- Non estrarre dati personali o dei clienti
- Rispetta
robots.txte i rate limit - Rispetta GDPR/CCPA se tratti dati personali (i dati del catalogo prodotto non sono personali)
- Identificati con una stringa User-Agent chiara
- Estrarre i dati del tuo Shopify store tramite l’Admin API è sempre consentito
Per un approfondimento, consulta il nostro articolo sulle .
Conclusione e takeaway principali
L’endpoint pubblico /products.json di Shopify rende l’estrazione dei dati ecommerce sorprendentemente semplice. Il flusso è: aggiungi /products.json → recupera con Python → fai la paginazione con ?limit=250&page= → appiattisci con pandas → esporta in CSV o Excel.
Cosa copre questa guida che altre non coprono:
- Reference completa dei campi: sai esattamente quali dati sono disponibili (oltre 40 campi tra prodotti, varianti e immagini) prima ancora di scrivere una riga di codice
- Endpoint aggiuntivi:
/collections.jsone/meta.jsonoffrono intelligence a livello di categoria e metadati dello store che nessun tutorial concorrente tratta - Tecniche pronte per la produzione: riuso della sessione, backoff esponenziale, header User-Agent e
?limit=250per gestire i rate limit reali - Export CSV/Excel corretto: dati appiattiti a livello di variante con pandas, non semplici dump di JSON grezzo
- Alternativa no-code: per chi preferisce la velocità alla flessibilità del codice
Per estrazioni Shopify una tantum o ricorrenti senza codice, prova la —il template Shopify Scraper gestisce tutto, dalla paginazione all’export. Per pipeline dati personalizzate o scraping su larga scala su molti store, lo script Python di questa guida ti offre pieno controllo.
Dai un’occhiata al per video tutorial, oppure esplora le nostre guide su e per tecniche correlate.
FAQ
Si può estrarre qualsiasi store Shopify con products.json?
La maggior parte degli store Shopify espone questo endpoint per impostazione predefinita: nei test, circa il 71% restituiva JSON valido. Alcuni store con configurazioni personalizzate o livelli di sicurezza aggiuntivi (Cloudflare, setup headless) possono restituire 404 o bloccare la richiesta. Il controllo rapido è semplice: visita {store-url}/products.json nel browser. Se vedi JSON, va bene.
È legale estrarre dati da Shopify?
I dati pubblici dei prodotti (prezzi, titoli, immagini, descrizioni) sono generalmente accessibili, e precedenti legali come hiQ v. LinkedIn supportano lo scraping di informazioni pubblicamente disponibili. Detto questo, controlla sempre i Termini di servizio del singolo store e le leggi del tuo paese. Non estrarre dati personali o dei clienti e rispetta i rate limit.
Quanti prodotti si possono estrarre da uno store Shopify?
Non esiste un limite massimo rigido sul totale. La paginazione con ?limit=250&page= ti permette di recuperare l’intero catalogo. Per store molto grandi (oltre 25.000 prodotti), usa il riutilizzo della sessione e pause tra richieste per evitare i rate limit. L’endpoint /meta.json può dirti in anticipo il numero esatto di prodotti, così sai quante pagine aspettarti.
Qual è la differenza tra products.json e la Shopify Admin API?
/products.json è un endpoint pubblico: nessuna autenticazione, solo dati prodotto in sola lettura, accessibili a chiunque. L’Admin API richiede token di accesso del proprietario dello store e fornisce ordini, quantità di inventario, dati clienti e accesso in scrittura. Se ti servono dati di vendita o i conteggi reali dell’inventario, serve l’accesso all’Admin API (quindi devi essere il proprietario dello store o avere la sua autorizzazione).
Posso estrarre dati da Shopify senza Python?
Assolutamente sì. Strumenti come ti permettono di estrarre dati da store Shopify da un’estensione Chrome, senza codice. Gestisce la paginazione in automatico ed esporta direttamente in CSV, Excel, Google Sheets, Airtable o Notion. Per gli sviluppatori che preferiscono altri linguaggi, lo stesso endpoint /products.json funziona con JavaScript, Ruby, Go—qualsiasi linguaggio capace di fare richieste HTTP e parsare JSON.
Scopri di più
