Το endpoint /products.json του Shopify είναι ένα από τα λιγότερο κρυφά «μυστικά» στα δεδομένα ecommerce. Πρόσθεσέ το σε οποιοδήποτε URL καταστήματος Shopify και θα πάρεις δομημένο JSON — χωρίς API keys, χωρίς αυθεντικοποίηση, χωρίς να χρειάζεται να κάνεις scraping μέσα από περίπλοκο HTML.
Εργάζομαι στην ομάδα του , οπότε περνάω πολύ χρόνο σκεφτόμενος πώς οι άνθρωποι εξάγουν δεδομένα από το web. Και το scraping του Shopify εμφανίζεται συνέχεια — ομάδες πωλήσεων που παρακολουθούν τιμές ανταγωνιστών, στελέχη ecommerce που συγκρίνουν καταλόγους προϊόντων, άνθρωποι procurement που ψάχνουν νέους προμηθευτές. Με στο Shopify και περίπου , ο όγκος των προϊόντων που μπορείς να εξαγάγεις είναι τεράστιος.
Αυτός ο οδηγός καλύπτει όλη τη διαδικασία: τι επιστρέφει το endpoint, πώς να κάνεις pagination σε χιλιάδες προϊόντα, πώς να χειρίζεσαι τα rate limits χωρίς να μπλοκάρεσαι και πώς να μετατρέπεις το nested JSON του Shopify σε καθαρό CSV ή Excel με pandas. Θα δούμε επίσης endpoints που σχεδόν κανείς δεν αναφέρει (/collections.json, /meta.json) και θα δείξω και μια no-code εναλλακτική για όσους προτιμούν να παραλείψουν εντελώς την Python.
Τι είναι το endpoint /products.json του Shopify (και γιατί κάνει το scraping εύκολο)
Κάθε κατάστημα Shopify διαθέτει ένα δημόσιο endpoint στη διεύθυνση {store-url}/products.json που επιστρέφει δομημένα δεδομένα προϊόντων. Χωρίς API keys. Χωρίς OAuth. Χωρίς καμία μορφή αυθεντικοποίησης. Απλώς προσθέτεις /products.json στο URL του καταστήματος και παίρνεις πίσω ένα JSON array με κάθε προϊόν του καταλόγου.
Δοκίμασέ το τώρα μόνος σου: άνοιξε το ή το στον browser σου. Θα δεις καθαρό, δομημένο JSON με τίτλους προϊόντων, τιμές, παραλλαγές, εικόνες, tags — τα πάντα.
Σύγκρινέ το με την εναλλακτική: να αναλύσεις τα HTML themes του Shopify, τα οποία είναι βαθιά φωλιασμένα, ασυνεπή από κατάστημα σε κατάστημα και αλλάζουν κάθε φορά που ο έμπορος ενημερώνει το theme. Να τι θα είχες να αντιμετωπίσεις:
Η προσέγγιση HTML (οδυνηρή):
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 (καθαρή):
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 κερδίζει σε συνέπεια, αξιοπιστία και ευκολία επεξεργασίας. Το endpoint υποστηρίζει επίσης δύο βασικές παραμέτρους query — ?limit= (έως 250 προϊόντα ανά σελίδα, με προεπιλογή τα 30) και ?page= για pagination — τις οποίες θα αξιοποιήσουμε εκτενώς στον κώδικα παρακάτω.
Σημαντική διάκριση: αυτό είναι ένα δημόσιο storefront endpoint, όχι το . Το Admin API απαιτεί access tokens του ιδιοκτήτη του καταστήματος και παρέχει δεδομένα παραγγελιών, επίπεδα αποθέματος και πληροφορίες πελατών. Το δημόσιο /products.json endpoint είναι μόνο για ανάγνωση και προσβάσιμο από οποιονδήποτε. Θα εξηγήσω αναλυτικά τη διαφορά αργότερα, γιατί υπάρχει μεγάλη σύγχυση γύρω από αυτό στα forums.
Μια προειδοποίηση: δεν εκθέτει κάθε κατάστημα Shopify αυτό το endpoint. Στις δοκιμές μου, περίπου το 71% των καταστημάτων επιστρέφουν έγκυρο JSON (allbirds.com, gymshark.com, colourpop.com, kyliecosmetics.com λειτουργούν όλα), ενώ ορισμένες προσαρμοσμένες ρυθμίσεις επιστρέφουν 404 (hiutdenim.co.uk, bombas.com). Ο γρήγορος έλεγχος είναι απλός: επισκέψου το {store-url}/products.json στον browser σου και δες τι εμφανίζεται.
Γιατί να κάνεις Scrape το Shopify με Python; Κορυφαίες επαγγελματικές χρήσεις
Γιατί να ασχοληθείς; Για το ROI. Το χρησιμοποιεί πλέον αυτοματοποιημένο price scraping για competitive intelligence, από μόλις 34% το 2020. Και η έρευνα δείχνει ότι μια . Τα δεδομένα έχουν πραγματική χρηματική αξία.
Οι πιο συνηθισμένες χρήσεις που βλέπω είναι οι εξής:
| Χρήση | Ποιον ωφελεί | Τι κερδίζετε |
|---|---|---|
| Παρακολούθηση τιμών ανταγωνιστών | Ομάδες ecommerce ops | Παρακολουθείτε αλλαγές τιμών, εκπτώσεις και τιμές σύγκρισης σε καταλόγους ανταγωνιστών |
| Έρευνα προϊόντων & sourcing | Procurement / merchandising | Συγκρίνετε χαρακτηριστικά προϊόντων, παραλλαγές, υλικά και διαθεσιμότητα |
| Lead generation | Ομάδες πωλήσεων | Εξάγετε ονόματα προμηθευτών, δεδομένα brand και στοιχεία επικοινωνίας από καταλόγους καταστημάτων |
| Ανάλυση αγοράς & κατηγορίας | Ομάδες marketing | Κατανοείτε το μείγμα προϊόντων, τα tags, τη δομή των συλλογών και τη θέση στην αγορά |
| Παρακολούθηση αποθέματος & διαθεσιμότητας | Ομάδες supply chain | Ελέγχετε διαχρονικά την κατάσταση αποθέματος σε επίπεδο παραλλαγής (available: true/false) |
| Εντοπισμός νέων προϊόντων | Ομάδες προϊόντων | Παρακολουθείτε timestamps created_at για να εντοπίζετε νέες κυκλοφορίες των ανταγωνιστών |
Η Python είναι το πιο φυσικό εργαλείο για αυτή τη δουλειά. Το χρησιμοποιεί Python ως κύρια γλώσσα, και το οικοσύστημα — requests για HTTP, pandas για επεξεργασία δεδομένων, httpx για async — κάνει πολύ εύκολο να περάσεις από το «έχω ένα URL» στο «έχω ένα spreadsheet» σε λιγότερες από 80 γραμμές κώδικα.
Πλήρης οδηγός πεδίων του products.json: τι περιέχει κάθε πεδίο
Κάθε ανταγωνιστικό tutorial σού δείχνει τα title, id και handle, και μετά προχωρά. Η απάντηση JSON του Shopify περιέχει πάνω από 40 πεδία σε προϊόντα, παραλλαγές, εικόνες και επιλογές. Το να ξέρεις τι υπάρχει διαθέσιμο πριν γράψεις τον κώδικα σε γλιτώνει από το να ξανακάνεις scraping αργότερα.
Αυτόν τον οδηγό τον συνέλεξα από ζωντανές απαντήσεις /products.json που έγιναν fetch στις 16 Απριλίου 2026. Η δομή είναι σταθερή σε όλα τα καταστήματα που εκθέτουν το endpoint.
Πεδία σε επίπεδο προϊόντος
| Πεδίο | Τύπος δεδομένων | Ενδεικτική τιμή | Επαγγελματική χρήση |
|---|---|---|---|
id | Integer | 123456789 | Μοναδικό αναγνωριστικό προϊόντος για απο-διπλοποίηση |
title | String | "Classic Blue Jeans" | Όνομα προϊόντος για καταλόγους και συγκρίσεις |
handle | String | "classic-blue-jeans" | URL slug — δημιουργήστε links σελίδων προϊόντος ως {store}/products/{handle} |
body_html | String (HTML) ή null | Our best-selling... | Περιγραφή προϊόντος για ανάλυση περιεχομένου και έρευνα SEO |
vendor | String | "Hiut Denim" | Όνομα brand / προμηθευτή για lead gen ή sourcing |
product_type | String | "Jeans" | Ταξινόμηση κατηγορίας για ανάλυση αγοράς |
created_at | ISO DateTime | "2024-01-15T10:30:00-05:00" | Παρακολούθηση του πότε προστέθηκαν τα προϊόντα (εντοπισμός νέων λανσαρισμάτων) |
updated_at | ISO DateTime | "2025-03-01T08:00:00-05:00" | Εντοπισμός πρόσφατων αλλαγών στον κατάλογο |
published_at | ISO DateTime | "2024-01-16T00:00:00-05:00" | Πότε εμφανίστηκαν τα προϊόντα στο storefront |
tags | Array of Strings | ["organic", "women", "straight-leg"] | Ανάλυση λέξεων-κλειδιών / tags για SEO, κατηγοριοποίηση και εντοπισμό τάσεων |
variants | Array of Objects | (δείτε τα πεδία παραλλαγών παρακάτω) | Τιμή, SKU, διαθεσιμότητα ανά παραλλαγή |
images | Array of Objects | (δείτε τα πεδία εικόνων παρακάτω) | URLs εικόνων προϊόντων για καταλόγους και οπτική ανάλυση |
options | Array of Objects | [{"name": "Size", "values": ["S","M","L"]}] | Κατανόηση της διαμόρφωσης του προϊόντος (μέγεθος, χρώμα, υλικό) |
Πεδία σε επίπεδο παραλλαγής (nested κάτω από κάθε προϊόν)
| Πεδίο | Τύπος δεδομένων | Ενδεικτικό παράδειγμα | Χρήση |
|---|---|---|---|
id | Integer | 987654321 | Μοναδικό αναγνωριστικό παραλλαγής |
title | String | "32 / Blue" | Εμφανιζόμενο όνομα παραλλαγής |
sku | String | "HD-BLU-32" | Αντιστοίχιση SKU για συστήματα αποθέματος |
price | String | "185.00" | Παρακολούθηση τιμών (σημείωση: είναι string, κάνε cast σε float για υπολογισμούς) |
compare_at_price | String ή null | "200.00" | Αρχική τιμή — απαραίτητη για παρακολούθηση εκπτώσεων |
available | Boolean | true | Διαθεσιμότητα αποθέματος (ο μόνος δημόσιος δείκτης stock) |
weight | Float | 1.2 | Ανάλυση αποστολής / logistics |
option1, option2, option3 | String | "32", "Blue", null | Επιμέρους τιμές επιλογών |
created_at, updated_at | ISO DateTime | — | Παρακολούθηση αλλαγών σε επίπεδο παραλλαγής |
Πεδία σε επίπεδο εικόνας
| Πεδίο | Τύπος δεδομένων | Ενδεικτικό παράδειγμα | Χρήση |
|---|---|---|---|
id | Integer | 111222333 | Μοναδικό αναγνωριστικό εικόνας |
src | String (URL) | "https://cdn.shopify.com/..." | Άμεσος σύνδεσμος λήψης εικόνας |
alt | String ή null | "Front view of jeans" | Alt text εικόνας για ανάλυση προσβασιμότητας |
position | Integer | 1 | Σειρά εμφάνισης εικόνων |
width, height | Integer | 2048, 2048 | Διαστάσεις εικόνας |
Τι ΔΕΝ περιλαμβάνεται στο δημόσιο endpoint
Ένα κρίσιμο σημείο που συχνά προκαλεί λάθος: το inventory_quantity ΔΕΝ είναι διαθέσιμο στις δημόσιες απαντήσεις /products.json. Αυτό το πεδίο αφαιρέθηκε από τα δημόσια JSON endpoints τον Δεκέμβριο του 2017 για λόγους ασφάλειας. Ο μόνος δείκτης stock που παίρνεις είναι το boolean πεδίο available σε κάθε παραλλαγή (true ή false). Για να δεις πραγματικές ποσότητες αποθέματος, χρειάζεσαι το authenticated Admin API με διαπιστευτήρια ιδιοκτήτη καταστήματος.
Πριν γράψεις τον κώδικα scraping, έλεγξε αυτόν τον πίνακα και αποφάσισε ποια πεδία σε ενδιαφέρουν. Αν κάνεις παρακολούθηση τιμών, χρειάζεσαι variants[].price, variants[].compare_at_price και variants[].available. Αν κάνεις lead generation, δώσε έμφαση στα vendor, product_type και tags. Φιλτράρισέ τα ανάλογα — το CSV σου θα είναι πολύ πιο καθαρό.
Πέρα από το products.json: Collections, Meta και άλλα Shopify endpoints
Κανένα ανταγωνιστικό tutorial δεν αναφέρει αυτά τα endpoints. Είναι απαραίτητα για σοβαρό competitive intelligence.
/collections.json — Όλες οι κατηγορίες του καταστήματος
Επιστρέφει κάθε συλλογή (κατηγορία) του καταστήματος με τίτλους, handles, περιγραφές και πλήθος προϊόντων. Το επιβεβαίωσα στα zoologistperfumes.com, allbirds.com και gymshark.com — όλα επέστρεψαν έγκυρο 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}
Θέλεις να καταλάβεις πώς οργανώνει ένας ανταγωνιστής τον κατάλογό του; Αυτό είναι το endpoint.
/collections/{handle}/products.json — Προϊόντα ανά κατηγορία
Επιστρέφει προϊόντα φιλτραρισμένα σε μια συγκεκριμένη συλλογή. Η ίδια δομή JSON με το /products.json, αλλά περιορισμένη σε μία κατηγορία. Αυτό είναι κρίσιμο για scraping σε επίπεδο κατηγορίας — για παράδειγμα, αν θέλεις να παρακολουθείς μόνο τη συλλογή «Sale» ή «New Arrivals» ενός ανταγωνιστή.
/meta.json — Μεταδεδομένα σε επίπεδο καταστήματος
Επιστρέφει όνομα καταστήματος, περιγραφή, νόμισμα, χώρα και — το καλύτερο — το published_products_count. Αυτός ο αριθμός σού επιτρέπει να υπολογίσεις εκ των προτέρων πόσες σελίδες pagination θα χρειαστείς: ceil(published_products_count / 250). Τέλος τα τυφλά βήματα σελίδα-σελίδα μέχρι να βρεις κενή απάντηση.
Ποιο endpoint πρέπει να χρησιμοποιήσεις;
| Τι θέλετε | Endpoint | Χρειάζεται auth; |
|---|---|---|
| Όλα τα προϊόντα (δημόσια) | /products.json | Όχι |
| Προϊόντα σε συγκεκριμένη κατηγορία | /collections/{handle}/products.json | Όχι |
| Metadata καταστήματος + πλήθος προϊόντων | /meta.json | Όχι |
| Όλες οι συλλογές (κατηγορίες) | /collections.json | Όχι |
| Δεδομένα παραγγελιών / πωλήσεων (μόνο δικό σας κατάστημα) | Admin API /orders.json | Ναι (API key) |
| Ποσότητες αποθέματος (μόνο δικό σας κατάστημα) | Admin API /inventory_levels.json | Ναι |
Η συχνή ερώτηση στα forums — «Μπορώ να κάνω scrape πόσες μονάδες πούλησε ένας ανταγωνιστής;» — έχει σύντομη απάντηση: όχι. Όχι από δημόσια endpoints. Τα δεδομένα πωλήσεων και οι ποσότητες αποθέματος απαιτούν το authenticated Admin API, άρα χρειάζεσαι πρόσβαση ιδιοκτήτη καταστήματος. Τα δημόσια endpoints δίνουν μόνο δεδομένα καταλόγου προϊόντων.

Πώς να κάνεις Scrape το Shopify με Python: Βήμα-βήμα εγκατάσταση
- Δυσκολία: Αρχάριος
- Χρόνος που απαιτείται: ~15 λεπτά (setup + πρώτο scrape)
- Τι θα χρειαστείς: Python 3.11+,
pip, ένα terminal και το URL ενός Shopify store για scraping
Βήμα 1: Εγκατέστησε την Python και τις απαραίτητες βιβλιοθήκες
Βεβαιώσου ότι έχεις εγκατεστημένη την Python 3.11 ή νεότερη (η pandas 3.0.x το απαιτεί). Στη συνέχεια εγκατέστησε τις δύο βιβλιοθήκες που χρειαζόμαστε:
1pip install requests pandas
Για export σε Excel, θα χρειαστείς επίσης:
1pip install openpyxl
Στην αρχή του script σου, πρόσθεσε αυτά τα imports:
1import requests
2import pandas as pd
3import time
4import random
5import json
Δεν θα πρέπει να εμφανιστούν σφάλματα import όταν εκτελέσεις το script. Αν η pandas εμφανίσει σφάλμα έκδοσης, αναβάθμισε την Python σε 3.12.
Βήμα 2: Ανάκτηση δεδομένων προϊόντων από το /products.json
Ορίστε μια βασική συνάρτηση που δέχεται το URL ενός καταστήματος, καλεί το endpoint και επιστρέφει το parsed JSON:
1def fetch_products_page(store_url, page=1, limit=250):
2 """Fetch a single page of products from a Shopify store."""
3 url = f"{store_url.rstrip('/')}/products.json"
4 params = {"limit": limit, "page": page}
5 headers = {
6 "User-Agent": "Mozilla/5.0 (compatible; ProductResearch/1.0)"
7 }
8 response = requests.get(url, params=params, headers=headers, timeout=30)
9 response.raise_for_status()
10 return response.json().get("products", [])
Βασικές λεπτομέρειες:
limit=250είναι το μέγιστο που επιτρέπει το Shopify ανά σελίδα. Η προεπιλογή είναι 30, οπότε ο ρητός ορισμός μειώνει τα συνολικά requests έως και 8 φορές.- Header
User-Agent: όρισε πάντα έναν ρεαλιστικό. Requests χωρίς User-Agent είναι πιο πιθανό να ενεργοποιήσουν τα anti-bot συστήματα του Shopify. timeout=30: μην αφήνεις ένα request να «κρεμάει» για πάντα.
Δοκίμασέ το με ένα γνωστό κατάστημα:
1products = fetch_products_page("https://allbirds.com")
2print(f"Fetched {len(products)} products")
3print(f"First product: {products[0]['title']}")
Θα πρέπει να δεις κάτι σαν: Fetched 250 products και τον τίτλο του πρώτου προϊόντος.
Βήμα 3: Χειρίσου το pagination για να κάνεις scrape όλα τα προϊόντα
Ένα μόνο request επιστρέφει το πολύ 250 προϊόντα. Τα περισσότερα καταστήματα έχουν περισσότερα από αυτά (το Allbirds έχει 1.420+). Πρέπει να κάνεις loop στις σελίδες μέχρι να λάβεις κενή απάντηση.
1def scrape_all_products(store_url, delay=1.0):
2 """Scrape all products from a Shopify store, handling pagination."""
3 all_products = []
4 page = 1
5 while True:
6 print(f"Fetching page {page}...")
7 products = fetch_products_page(store_url, page=page, limit=250)
8 if not products:
9 print(f"No more products. Total: {len(all_products)}")
10 break
11 all_products.extend(products)
12 print(f" Got {len(products)} products (total so far: {len(all_products)})")
13 page += 1
14 # Be polite: wait between requests
15 time.sleep(delay + random.uniform(0, 0.5))
16 return all_products
Όταν το products επιστρέψει κενό, έχεις φτάσει στο τέλος.
Το time.sleep() με τυχαίο jitter σε κρατά κάτω από το ανεπίσημο rate limit του Shopify (~2 requests/δευτερόλεπτο).
Χρήσιμη συμβουλή: Αν πρώτα κάλεσες το /meta.json, ήδη ξέρεις το συνολικό πλήθος προϊόντων και μπορείς να υπολογίσεις ακριβώς πόσες σελίδες χρειάζεσαι: pages = ceil(product_count / 250). Έτσι αποφεύγεις το μοτίβο «ένα επιπλέον κενό request στο τέλος».
Βήμα 4: Ανάλυσε και επίλεξε τα πεδία που χρειάζεσαι
Τώρα που έχεις όλα τα προϊόντα ως Python list από dictionaries, εξήγαγε μόνο τα πεδία που σε ενδιαφέρουν. Ακολουθεί ένα παράδειγμα που τραβά τα πιο συνηθισμένα πεδία για παρακολούθηση τιμών:
1def extract_product_data(products):
2 """Extract key fields from products, flattening variants."""
3 rows = []
4 for product in products:
5 for variant in product.get("variants", []):
6 rows.append({
7 "product_id": product["id"],
8 "title": product["title"],
9 "handle": product["handle"],
10 "vendor": product.get("vendor", ""),
11 "product_type": product.get("product_type", ""),
12 "tags": ", ".join(product.get("tags", [])),
13 "created_at": product.get("created_at", ""),
14 "variant_id": variant["id"],
15 "variant_title": variant.get("title", ""),
16 "sku": variant.get("sku", ""),
17 "price": variant.get("price", ""),
18 "compare_at_price": variant.get("compare_at_price", ""),
19 "available": variant.get("available", ""),
20 "image_url": product["images"][0]["src"] if product.get("images") else ""
21 })
22 return rows
Αυτό δημιουργεί μία γραμμή ανά παραλλαγή — το πιο χρήσιμο format για price comparison, αφού ένα μόνο προϊόν όπως το "Classic Blue Jeans" μπορεί να έχει 12 παραλλαγές (6 μεγέθη × 2 χρώματα), καθεμία με τη δική της τιμή και διαθεσιμότητα.
Εξαγωγή scraped δεδομένων Shopify σε CSV και Excel με pandas
Κάθε άλλο tutorial για Shopify scraping απλώς πετά το raw JSON σε ένα αρχείο και σταματά εκεί. Κατάλληλο για developers. Άχρηστο για τον ecommerce analyst που χρειάζεται ένα spreadsheet μέχρι την Παρασκευή.
Το πρόβλημα: το JSON του Shopify είναι nested. Ένα προϊόν μπορεί να περιέχει δώδεκα παραλλαγές, η καθεμία με τη δική της τιμή, SKU και διαθεσιμότητα. Το να το μετατρέψεις αυτό σε γραμμές και στήλες θέλει λίγη δουλειά με pandas.
Μετατρέψτε το nested JSON σε καθαρό πίνακα
Υπάρχουν δύο προσεγγίσεις, ανάλογα με τη χρήση σου:
Επιλογή A: Μία γραμμή ανά παραλλαγή (η καλύτερη για παρακολούθηση τιμών και αποθέματος)
1# Using the extract_product_data function from Step 4
2products = scrape_all_products("https://allbirds.com")
3rows = extract_product_data(products)
4df = pd.DataFrame(rows)
5print(f"DataFrame shape: {df.shape}")
6print(df.head())
Αυτό σου δίνει έναν επίπεδο πίνακα όπου κάθε γραμμή είναι ένας μοναδικός συνδυασμός προϊόντος-παραλλαγής. Ένα κατάστημα με 500 προϊόντα και κατά μέσο όρο 4 παραλλαγές ανά προϊόν θα δώσει DataFrame περίπου 2.000 γραμμών.
Επιλογή B: Μία γραμμή ανά σύνοψη προϊόντος (η καλύτερη για επισκόπηση καταλόγου)
1def summarize_products(products):
2 """One row per product with min/max price across variants."""
3 rows = []
4 for product in products:
5 prices = [float(v["price"]) for v in product.get("variants", []) if v.get("price")]
6 rows.append({
7 "product_id": product["id"],
8 "title": product["title"],
9 "vendor": product.get("vendor", ""),
10 "product_type": product.get("product_type", ""),
11 "variant_count": len(product.get("variants", [])),
12 "min_price": min(prices) if prices else None,
13 "max_price": max(prices) if prices else None,
14 "any_available": any(v.get("available", False) for v in product.get("variants", [])),
15 "tags": ", ".join(product.get("tags", []))
16 })
17 return rows
Export σε CSV, Excel και Google Sheets
1# CSV export (use utf-8-sig so Excel handles special characters)
2df.to_csv("shopify_products.csv", index=False, encoding="utf-8-sig")
3# Excel export (requires openpyxl)
4df.to_excel("shopify_products.xlsx", index=False, engine="openpyxl")
5print("Exported to shopify_products.csv and shopify_products.xlsx")
Για Google Sheets, μπορείς να χρησιμοποιήσεις τη βιβλιοθήκη gspread με service account, αλλά ειλικρινά — για τις περισσότερες χρήσεις, το export σε CSV και το upload στο Google Drive είναι πιο γρήγορο και πιο απλό.
Scraping έτοιμο για παραγωγή: Rate limits, retries και anti-blocking
Το βασικό script δουλεύει μια χαρά για μικρά καταστήματα. Scraping σε κατάστημα με 5.000+ προϊόντα ή σε πολλά καταστήματα διαδοχικά; Εκεί αρχίζουν τα προβλήματα.
Κατανοώντας τα rate limits και τη συμπεριφορά μπλοκαρίσματος του Shopify
Τα δημόσια JSON endpoints του Shopify δεν έχουν επίσημα τεκμηριωμένα rate limits (σε αντίθεση με το leaky bucket μοντέλο του Admin API), αλλά από πρακτικές δοκιμές προκύπτει ότι:
- Ασφαλής ρυθμός: περίπου 2 requests το δευτερόλεπτο ανά κατάστημα
- Soft ceiling: περίπου 40 requests το λεπτό πριν αρχίσει το throttling
- HTTP 429: "Too Many Requests" — η κλασική απάντηση για rate limit
- HTTP 430: Κωδικός ειδικός του Shopify που δείχνει block σε επίπεδο ασφάλειας (όχι απλώς rate limiting)
- HTTP 403 ή redirect σε CAPTCHA: Σε ορισμένα καταστήματα με επιπλέον προστασία Cloudflare
Requests από κοινόχρηστη cloud υποδομή (AWS Lambda, Google Cloud Run) είναι ιδιαίτερα πιθανό να προκαλέσουν μπλοκαρίσματα, επειδή αυτά τα IP ranges έχουν υψηλή συχνότητα abuse.
Τεχνικές για αξιόπιστο Shopify scraping
Ακολουθεί η εξέλιξη από το «δουλεύει στο laptop μου» στο «τρέχει σε παραγωγή»:
| Επίπεδο | Τεχνική | Αξιοπιστία |
|---|---|---|
| Βασικό | requests.get() + ?page= | Σπάει σε μεγάλους καταλόγους, μπορεί να μπλοκαριστεί |
| Ενδιάμεσο | requests.Session() + ?limit=250 + time.sleep(1) + retry στο 429 | Δουλεύει για τα περισσότερα καταστήματα |
| Προχωρημένο | Async httpx + περιστρεφόμενο User-Agent + exponential backoff | Επιπέδου παραγωγής, κλιμακώνεται σε 10K+ προϊόντα |
Ενδιάμεσο επίπεδο (προτείνεται για τους περισσότερους χρήστες):
1import requests
2from requests.adapters import HTTPAdapter
3from urllib3.util.retry import Retry
4def create_session():
5 """Create a requests session with automatic retry logic."""
6 session = requests.Session()
7 retries = Retry(
8 total=5,
9 backoff_factor=1, # sleep: 0.5s, 1s, 2s, 4s, 8s
10 status_forcelist=[429, 430, 500, 502, 503, 504],
11 respect_retry_after_header=True
12 )
13 session.mount("https://", HTTPAdapter(max_retries=retries))
14 session.headers.update({
15 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
16 })
17 return session
Η ρύθμιση Retry χειρίζεται αυτόματα τις απαντήσεις 429 με exponential backoff. Το backoff_factor=1 σημαίνει ότι η ακολουθία αναμονής είναι 0,5s → 1s → 2s → 4s → 8s ανάμεσα στα retries. Η επαναχρησιμοποίηση της session (requests.Session()) σου δίνει επίσης connection pooling, που μειώνει το overhead όταν κάνεις πολλά requests στο ίδιο domain.
Περιστροφή User-Agent: Αν κάνεις scraping σε πολλά καταστήματα, εναλλάσσεις μεταξύ 3–5 ρεαλιστικών browser User-Agent strings. Δεν πρόκειται για εξαπάτηση — πρόκειται για το να μην φαίνεσαι σαν bot που στέλνει πάντα τα ίδια headers σε κάθε request.
Πλήρες λειτουργικό Python script για Shopify scraping με export σε CSV
Ορίστε το πλήρες script, έτοιμο για copy-paste, που συνδυάζει όλα τα παραπάνω. Είναι περίπου 75 γραμμές πραγματικού κώδικα (συν σχόλια), και το έχω δοκιμάσει στο Allbirds (1.420 προϊόντα), στο ColourPop (2.000+ προϊόντα) και στο Zoologist Perfumes (μικρός κατάλογος).
1import requests
2import pandas as pd
3import time
4import random
5from requests.adapters import HTTPAdapter
6from urllib3.util.retry import Retry
7def create_session():
8 """Create a session with retry logic for rate limits."""
9 session = requests.Session()
10 retries = Retry(
11 total=5,
12 backoff_factor=1,
13 status_forcelist=[429, 430, 500, 502, 503, 504],
14 respect_retry_after_header=True
15 )
16 session.mount("https://", HTTPAdapter(max_retries=retries))
17 session.headers.update({
18 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
19 "AppleWebKit/537.36 (KHTML, like Gecko) "
20 "Chrome/125.0.0.0 Safari/537.36"
21 })
22 return session
23def scrape_shopify(store_url, delay=1.0):
24 """Scrape all products from a Shopify store via /products.json."""
25 session = create_session()
26 all_products = []
27 page = 1
28 base_url = f"{store_url.rstrip('/')}/products.json"
29 while True:
30 print(f" Page {page}...", end=" ")
31 resp = session.get(base_url, params={"limit": 250, "page": page}, timeout=30)
32 resp.raise_for_status()
33 products = resp.json().get("products", [])
34 if not products:
35 break
36 all_products.extend(products)
37 print(f"{len(products)} products (total: {len(all_products)})")
38 page += 1
39 time.sleep(delay + random.uniform(0, 0.5))
40 return all_products
41def flatten_to_variants(products):
42 """Flatten nested product JSON into one row per variant."""
43 rows = []
44 for p in products:
45 base = {
46 "product_id": p["id"],
47 "title": p["title"],
48 "handle": p["handle"],
49 "vendor": p.get("vendor", ""),
50 "product_type": p.get("product_type", ""),
51 "tags": ", ".join(p.get("tags", [])),
52 "created_at": p.get("created_at", ""),
53 "updated_at": p.get("updated_at", ""),
54 "image_url": p["images"][0]["src"] if p.get("images") else "",
55 }
56 for v in p.get("variants", []):
57 row = {**base}
58 row["variant_id"] = v["id"]
59 row["variant_title"] = v.get("title", "")
60 row["sku"] = v.get("sku", "")
61 row["price"] = v.get("price", "")
62 row["compare_at_price"] = v.get("compare_at_price", "")
63 row["available"] = v.get("available", "")
64 rows.append(row)
65 return rows
66if __name__ == "__main__":
67 STORE_URL = "https://allbirds.com" # Change this to your target store
68 OUTPUT_CSV = "shopify_products.csv"
69 OUTPUT_EXCEL = "shopify_products.xlsx"
70 print(f"Scraping {STORE_URL}...")
71 products = scrape_shopify(STORE_URL)
72 print(f"\nTotal products scraped: {len(products)}")
73 print("Flattening to variant-level rows...")
74 rows = flatten_to_variants(products)
75 df = pd.DataFrame(rows)
76 print(f"DataFrame: {df.shape[0]} rows x {df.shape[1]} columns")
77 df.to_csv(OUTPUT_CSV, index=False, encoding="utf-8-sig")
78 df.to_excel(OUTPUT_EXCEL, index=False, engine="openpyxl")
79 print(f"\nExported to {OUTPUT_CSV} and {OUTPUT_EXCEL}")
Τρέξ’ το με python scrape_shopify.py. Για το Allbirds, αυτό διαρκεί περίπου 45 δευτερόλεπτα και παράγει ένα CSV με ~5.000+ γραμμές (μία ανά παραλλαγή). Η έξοδος στο terminal μοιάζει κάπως έτσι:
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
Παράκαμψη της Python: Scrape το Shopify σε 2 κλικ με το Thunderbit (no-code εναλλακτική)
Δεν θέλουν όλοι να εγκαταστήσουν Python, να διορθώνουν σφάλματα import ή να συντηρούν ένα scraping script. Για τον sales rep που χρειάζεται τιμές ανταγωνιστών μέχρι αύριο το πρωί, η Python είναι υπερβολή.
Γι’ αυτό δημιουργήσαμε το — ένα AI web scraper που λειτουργεί ως Chrome extension. Χωρίς κώδικα, χωρίς API keys, χωρίς ρύθμιση περιβάλλοντος.
Πώς το Thunderbit κάνει Scrape τα Shopify stores
Το Thunderbit διαθέτει ένα ειδικό Shopify Scraper template που είναι προρυθμισμένο για σελίδες προϊόντων Shopify. Εγκαθιστάς το , πηγαίνεις σε ένα Shopify store και πατάς «Scrape». Το template εξάγει αυτόματα ονόματα προϊόντων, περιγραφές, τιμές, στοιχεία παραλλαγών, εικόνες και πληροφορίες προμηθευτή.
Για καταστήματα όπου το template δεν ταιριάζει τέλεια (custom themes, ασυνήθιστες διατάξεις), η λειτουργία AI Suggest Fields του Thunderbit διαβάζει τη σελίδα και δημιουργεί αυτόματα ονόματα στηλών. Μπορείς να τα προσαρμόσεις — να μετονομάσεις στήλες, να προσθέσεις πεδία, να γράψεις οδηγίες όπως «να εξάγονται μόνο προϊόντα με συμπληρωμένο compare_at_price».
Λίγες δυνατότητες που αντιστοιχούν άμεσα σε ό,τι κάνει το Python script:
- Subpage scraping: Επισκέπτεται αυτόματα κάθε σελίδα προϊόντος και εμπλουτίζει τον πίνακα με πλήρεις περιγραφές, reviews ή στοιχεία παραλλαγών — το ίδιο που πετυχαίνει το Python script μας με επανάληψη σελίδων, αλλά χωρίς κώδικα.
- Automatic pagination: Διαχειρίζεται αυτόματα το pagination και το infinite scroll χωρίς ρυθμίσεις.
- Scheduled scraping: Ρυθμίζεις επαναλαμβανόμενες εργασίες (π.χ. «κάθε Δευτέρα στις 9 π.μ.») για συνεχή παρακολούθηση τιμών — χωρίς cron job ή server.
- Δωρεάν export σε CSV, Excel, Google Sheets, Airtable ή Notion σε όλα τα πλάνα.
Python script vs. Thunderbit: ειλικρινής σύγκριση
| Παράγοντας | Python Script | Thunderbit (No-Code) |
|---|---|---|
| Χρόνος εγκατάστασης | 15–60 λεπτά (περιβάλλον + κώδικας) | ~2 λεπτά (εγκατάσταση Chrome extension) |
| Απαιτείται coding | Ναι (Python) | Όχι |
| Παραμετροποίηση | Απεριόριστη | Προτεινόμενα πεδία με AI + custom prompts |
| Χειρισμός pagination | Πρέπει να γραφτεί χειροκίνητα | Αυτόματα |
| Μορφές export | Πρέπει να το γράψεις μόνος σου (CSV/Excel) | CSV, Excel, Google Sheets, Airtable, Notion (δωρεάν) |
| Προγραμματισμένες εκτελέσεις | Cron job + hosting | Ενσωματωμένος scheduler |
| Χειρισμός rate limits | Πρέπει να γράψεις retries/backoff | Χειρίζεται αυτόματα |
| Ιδανικό για | Developers, data pipelines μεγάλης κλίμακας | Business users, γρήγορες εξαγωγές, επαναλαμβανόμενη παρακολούθηση |
Χρησιμοποίησε Python όταν χρειάζεσαι πλήρη έλεγχο ή όταν το εντάσσεις σε μεγαλύτερο data pipeline. Χρησιμοποίησε το Thunderbit όταν χρειάζεσαι δεδομένα άμεσα και δεν θέλεις να συντηρείς κώδικα. Για πιο αναλυτική ματιά στο , έχουμε γράψει ξεχωριστό οδηγό πάνω σε αυτό.

Tips και βέλτιστες πρακτικές για scraping Shopify stores
Αυτά ισχύουν ανεξάρτητα από το εργαλείο που θα επιλέξεις:
- Χρησιμοποίησε πάντα
?limit=250για να ελαχιστοποιείς τα συνολικά requests. Η προεπιλογή των 30 ανά σελίδα σημαίνει 8 φορές περισσότερα requests για τα ίδια δεδομένα. - Σεβαστείτε το κατάστημα: βάλε καθυστερήσεις 1–2 δευτερολέπτων ανάμεσα στα requests. Το να «χτυπάς» έναν server με διαδοχικά requests είναι κακή πρακτική και αυξάνει τις πιθανότητες μπλοκαρίσματος.
- Έλεγξε πρώτα το
robots.txt: το προεπιλεγμένοrobots.txtτου Shopify ΔΕΝ μπλοκάρει το/products.json. Όμως ορισμένα καταστήματα προσθέτουν custom κανόνες, οπότε επαλήθευσέ το πριν κάνεις scraping σε μεγάλη κλίμακα. - Αποθήκευσε πρώτα το raw JSON τοπικά και μετά επεξεργάσου το. Αν αλλάξει αργότερα η λογική parsing, δεν θα χρειαστεί να ξανακάνεις scraping. Ένα απλό
json.dump(all_products, open("raw_data.json", "w"))πριν το flattening σε γλιτώνει από πονοκέφαλο. - Κάνε deduplicate με βάση το
product.id: σε οριακές περιπτώσεις pagination μπορεί να επιστρέψει διπλότυπα προϊόντα στα όρια των σελίδων. Ένα γρήγοροdf.drop_duplicates(subset=["product_id", "variant_id"])το καθαρίζει. - Μετέτρεψε το
priceσε float πριν κάνεις υπολογισμούς. Το Shopify επιστρέφει τις τιμές ως strings ("185.00"), όχι ως αριθμούς. - Παρακολούθησε αλλαγές στο endpoint: παρότι το
/products.jsonείναι σταθερό εδώ και χρόνια, θεωρητικά το Shopify θα μπορούσε να το περιορίσει. Αν ξαφνικά ο scraper σου αρχίσει να παίρνει 404, έλεγξε πρώτα χειροκίνητα το κατάστημα.
Για περισσότερα σχετικά με τη δημιουργία ανθεκτικών scrapers, δες τον οδηγό μας για τις .
Νομικές και ηθικές παράμετροι στο scraping Shopify
Σύντομη ενότητα, αλλά σημαντική.
Το endpoint /products.json παρέχει δημόσια διαθέσιμα δεδομένα προϊόντων — τις ίδιες πληροφορίες που βλέπει κάθε επισκέπτης όταν περιηγείται στο κατάστημα. Οι Όροι Χρήσης του Shopify περιλαμβάνουν διατύπωση σχετικά με το να μην χρησιμοποιούνται «αυτοματοποιημένα μέσα» για πρόσβαση στις «Υπηρεσίες», αλλά αυτή η διατύπωση αναφέρεται στην ίδια την πλατφόρμα (admin dashboard, checkout), όχι στα δημόσια δεδομένα του storefront. Μέχρι τον Απρίλιο του 2026 δεν έχουν κατατεθεί αγωγές scraping ειδικά για το Shopify.
Σημαντικά νομικά προηγούμενα στηρίζουν το scraping δημόσιων δεδομένων: η υπόθεση hiQ v. LinkedIn έδειξε ότι το scraping δημόσια προσβάσιμων δεδομένων δεν παραβιάζει τον CFAA, και η Meta v. Bright Data (2024) έκρινε ότι οι περιορισμοί των TOS ισχύουν μόνο όταν ο χρήστης είναι συνδεδεμένος.
Βέλτιστες πρακτικές:
- Κάνε scraping μόνο δημόσια διαθέσιμων δεδομένων προϊόντων
- Μην κάνεις scraping προσωπικών ή πελατειακών δεδομένων
- Σεβάσου το
robots.txtκαι τα rate limits - Συμμορφώσου με GDPR/CCPA αν χειρίζεσαι οποιαδήποτε προσωπικά δεδομένα (τα δεδομένα καταλόγου προϊόντων δεν είναι προσωπικά)
- Δήλωσε καθαρά το User-Agent σου
- Το scraping του δικού σου Shopify store μέσω του Admin API είναι πάντα αποδεκτό
Για πιο αναλυτική συζήτηση, δες το άρθρο μας για τις .
Συμπέρασμα και βασικά συμπεράσματα
Το δημόσιο endpoint /products.json του Shopify κάνει την εξαγωγή δεδομένων ecommerce όσο εύκολη γίνεται. Η ροή είναι: προσθέτεις /products.json → κάνεις fetch με Python → pagination με ?limit=250&page= → flatten με pandas → export σε CSV ή Excel.
Τι καλύπτει αυτός ο οδηγός που δεν καλύπτουν άλλοι:
- Πλήρης αναφορά πεδίων: Ξέρεις ακριβώς ποια δεδομένα είναι διαθέσιμα (40+ πεδία σε προϊόντα, παραλλαγές και εικόνες) πριν γράψεις ούτε μία γραμμή κώδικα
- Πρόσθετα endpoints: Τα
/collections.jsonκαι/meta.jsonσού δίνουν intelligence σε επίπεδο κατηγορίας και metadata καταστήματος που κανένα ανταγωνιστικό tutorial δεν καλύπτει - Τεχνικές έτοιμες για παραγωγή: Επαναχρησιμοποίηση session, exponential backoff, headers User-Agent και
?limit=250για διαχείριση πραγματικών rate limits - Σωστό export σε CSV/Excel: Flattened δεδομένα σε επίπεδο παραλλαγής με pandas, όχι απλώς raw JSON dumps
- No-code εναλλακτική: Το για όσους προτιμούν την ταχύτητα από την ευελιξία του κώδικα
Για one-off ή επαναλαμβανόμενες εξαγωγές δεδομένων Shopify χωρίς κώδικα, δοκίμασε το — το Shopify Scraper template τα αναλαμβάνει όλα, από το pagination μέχρι το export. Για custom data pipelines ή scraping σε μεγάλη κλίμακα σε πολλά καταστήματα, το Python script σε αυτόν τον οδηγό σού δίνει πλήρη έλεγχο.
Δες το για video walkthroughs ή εξερεύνησε τους οδηγούς μας για και για σχετικές τεχνικές.
Συχνές ερωτήσεις
Μπορείτε να κάνετε scrape οποιοδήποτε Shopify store με το products.json;
Τα περισσότερα Shopify stores εκθέτουν αυτό το endpoint από προεπιλογή — στις δοκιμές, περίπου το 71% επέστρεψε έγκυρο JSON. Ορισμένα stores με custom ρυθμίσεις ή επιπλέον επίπεδα ασφάλειας (Cloudflare, headless setups) μπορεί να επιστρέψουν 404 ή να μπλοκάρουν το request. Ο γρήγορος έλεγχος είναι να επισκεφθείς το {store-url}/products.json στον browser σου. Αν δεις JSON, είσαι έτοιμος.
Είναι νόμιμο το scraping Shopify stores;
Τα δημόσια δεδομένα προϊόντων (τιμές, τίτλοι, εικόνες, περιγραφές) είναι γενικά προσβάσιμα, και νομικά προηγούμενα όπως το hiQ v. LinkedIn στηρίζουν το scraping δημοσίως διαθέσιμων πληροφοριών. Παρ’ όλα αυτά, πάντα να ελέγχεις τους συγκεκριμένους Όρους Χρήσης του καταστήματος και τους τοπικούς νόμους σου. Μην κάνεις scraping προσωπικών ή πελατειακών δεδομένων και να σέβεσαι τα rate limits.
Πόσα προϊόντα μπορείτε να κάνετε scrape από ένα Shopify store;
Δεν υπάρχει σκληρό συνολικό όριο. Το pagination με ?limit=250&page= σού επιτρέπει να ανακτήσεις ολόκληρο τον κατάλογο. Για πολύ μεγάλα καταστήματα (25.000+ προϊόντα), χρησιμοποίησε επαναχρησιμοποίηση session και καθυστερήσεις για να αποφύγεις τα rate limits. Το endpoint /meta.json μπορεί να σου πει εκ των προτέρων το ακριβές πλήθος προϊόντων, ώστε να ξέρεις πόσες σελίδες να περιμένεις.
Ποια είναι η διαφορά μεταξύ products.json και του Shopify Admin API;
Το /products.json είναι δημόσιο endpoint — χωρίς αυθεντικοποίηση, μόνο για ανάγνωση, προσβάσιμο από οποιονδήποτε. Το Admin API απαιτεί access tokens του ιδιοκτήτη του καταστήματος και παρέχει παραγγελίες, ποσότητες αποθέματος, δεδομένα πελατών και δυνατότητα εγγραφής. Αν χρειάζεσαι δεδομένα πωλήσεων ή πραγματικές ποσότητες αποθέματος, χρειάζεσαι πρόσβαση στο Admin API (δηλαδή να είσαι ο ιδιοκτήτης του καταστήματος ή να έχεις την άδειά του).
Μπορώ να κάνω scrape το Shopify χωρίς Python;
Απολύτως. Εργαλεία όπως το σού επιτρέπουν να κάνεις scrape Shopify stores από Chrome extension χωρίς κώδικα. Διαχειρίζεται αυτόματα το pagination και κάνει export απευθείας σε CSV, Excel, Google Sheets, Airtable ή Notion. Για developers που προτιμούν άλλες γλώσσες, το ίδιο endpoint /products.json λειτουργεί με JavaScript, Ruby, Go — οποιαδήποτε γλώσσα μπορεί να κάνει HTTP requests και να αναλύει JSON.
Μάθε περισσότερα