אוטומציה של מחקר שוק: איך לגרד נתונים מ‑Shopify עם Python

עודכן לאחרונה ב-April 16, 2026

נקודת הקצה /products.json של Shopify היא אחד הסודות הגלויים ביותר בעולם נתוני האיקומרס. פשוט מוסיפים אותה לכתובת של כל חנות Shopify, ומקבלים בחזרה JSON מובנה — בלי מפתחות API, בלי אימות, ובלי צורך לגרד HTML מקונן.

אני עובד בצוות של , ולכן אני מבלה לא מעט זמן במחשבה על האופן שבו אנשים מחלצים נתונים מהאינטרנט. וגרידה מ‑Shopify עולה שוב ושוב — צוותי מכירות שעוקבים אחרי מחירי מתחרים, אנשי תפעול באיקומרס שמשווים קטלוגים, ואנשי רכש שמאתרים ספקים חדשים. עם ב‑Shopify ונתח של כ‑, כמות נתוני המוצרים שאפשר לגרד היא עצומה.

המדריך הזה מכסה את כל התהליך: מה מחזירה נקודת הקצה, איך עוברים בין אלפי מוצרים בעזרת pagination, איך מתמודדים עם מגבלות קצב בלי להיחסם, ואיך משטחים את ה‑JSON המקונן של Shopify לקובץ CSV או Excel מסודר באמצעות pandas. אכסה גם נקודות קצה שכמעט אף אחד לא מדבר עליהן (/collections.json, /meta.json) ואציג חלופה ללא קוד למי שמעדיף לוותר לגמרי על Python.

מהי נקודת הקצה /products.json של Shopify, ולמה היא הופכת את הגרידה לקלה כל כך?

לכל חנות Shopify יש נקודת קצה ציבורית בכתובת {store-url}/products.json שמחזירה נתוני מוצרים מובנים. בלי מפתחות API. בלי OAuth. בלי שום אימות. פשוט מוסיפים /products.json לכתובת החנות ומקבלים מערך JSON של כל המוצרים בקטלוג.

נסו בעצמכם עכשיו: פתחו בדפדפן את או את . תראו JSON נקי ומובנה עם כותרות מוצרים, מחירים, וריאנטים, תמונות, תגיות — הכול.

השוו זאת לחלופה: ניתוח של תבניות ה‑HTML של Shopify, שהן מקוננות מאוד, לא אחידות בין חנויות, ומשתנות בכל פעם שסוחר מעדכן את התבנית שלו. הנה מה שבדרך כלל תצטרכו להתמודד איתו:

שיטת ה‑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 מנצח בעקביות, אמינות וקלות ניתוח. נקודת הקצה תומכת גם בשני פרמטרי שאילתה חשובים — ?limit= (עד 250 מוצרים לעמוד, ברירת המחדל היא 30) ו‑?page= ל‑pagination — ונשתמש בהם הרבה בקוד שבהמשך.

הבחנה חשובה: זו נקודת קצה ציבורית של חנות הוויטרינה, לא ה‑. ה‑Admin API דורש אסימוני גישה של בעל החנות ומספק נתוני הזמנות, רמות מלאי ומידע על לקוחות. לעומת זאת, /products.json הציבורית מחזירה רק נתוני מוצר לקריאה בלבד, שכל אחד יכול לגשת אליהם. אסביר את ההבדל בהמשך, כי יש הרבה בלבול סביב זה בפורומים.

הערת זהירות: לא כל חנות Shopify חושפת את הנקודה הזו. בבדיקות שלי, בערך 71% מהחנויות מחזירות JSON תקין (allbirds.com, gymshark.com, colourpop.com, kyliecosmetics.com — כולן עובדות), בעוד שחלק מהתצורות המותאמות אישית מחזירות 404 (hiutdenim.co.uk, bombas.com). בדיקה מהירה פשוטה: נכנסים ל‑{store-url}/products.json בדפדפן ורואים מה מתקבל.

למה לגרד Shopify עם Python? מקרי שימוש עסקיים מובילים

למה בכלל להתאמץ? ROI. כבר משתמשים בגרידת מחירים אוטומטית לצורך מודיעין תחרותי, לעומת 34% בלבד בשנת 2020. ומחקרים מראים ששיפור של . הנתונים האלה שווים כסף אמיתי.

אלו מקרי השימוש הנפוצים ביותר שאני רואה:

מקרה שימושמי מרוויחמה מקבלים
מעקב אחר מחירי מתחריםצוותי תפעול באיקומרסמעקב אחר שינויי מחירים, הנחות ומחירי השוואה בקטלוגים של מתחרים
מחקר מוצרים ואיתור מקורות אספקהרכש / מרצ'נדייזינגהשוואת מאפייני מוצר, וריאנטים, חומרים וזמינות
יצירת לידיםצוותי מכירותחילוץ שמות ספקים, נתוני מותג ופרטי קשר מקטלוגים
ניתוח שוק וקטגוריותצוותי שיווקהבנה של תמהיל מוצרים, תגיות, מבנה קולקציות ומיצוב
מעקב אחר מלאי וזמינותצוותי שרשרת אספקהניטור מצב מלאי ברמת וריאנט (available: true/false) לאורך זמן
זיהוי מוצרים חדשיםצוותי מוצרמעקב אחר חותמות זמן של created_at כדי לזהות השקות חדשות של מתחרים

Python הוא הכלי הטבעי למשימה הזו. משתמשים ב‑Python כשפת העבודה הראשית שלהם, והאקוסיסטם — requests ל‑HTTP, pandas לעיבוד נתונים, httpx לעבודה אסינכרונית — הופך את הדרך מ‑"יש לי URL" ל‑"יש לי גיליון נתונים" לפשוטה מאוד, אפילו בפחות מ‑80 שורות קוד.

פירוט מלא של שדות products.json: הסבר על כל שדה

בכל מדריך מתחרה יראו לכם את title, id ו‑handle, ואז יעברו הלאה. אבל תגובת ה‑JSON של Shopify מכילה יותר מ‑40 שדות על פני מוצרים, וריאנטים, תמונות ואפשרויות. לדעת מה זמין לפני שכותבים את קוד הגרידה חוסך גרידות חוזרות בהמשך.

הפירוט הזה מבוסס על תגובות חיות של /products.json שנשלפו ב‑16 באפריל 2026. המבנה עקבי בכל החנויות שחושפות את הנקודה הזו.

שדות ברמת המוצר

שדהסוג נתוניםערך לדוגמהשימוש עסקי
idמספר שלם123456789מזהה מוצר ייחודי לצורך מניעת כפילויות
titleמחרוזת"Classic Blue Jeans"שם המוצר לקטלוגים והשוואות
handleמחרוזת"classic-blue-jeans"סלאג של ה‑URL — בונים קישור לעמוד המוצר כ‑{store}/products/{handle}
body_htmlמחרוזת (HTML) או null

Our best-selling...

תיאור מוצר לניתוח תוכן ומחקר SEO
vendorמחרוזת"Hiut Denim"שם מותג/ספק ליצירת לידים או איתור מקורות
product_typeמחרוזת"Jeans"סיווג קטגוריה לניתוח שוק
created_atתאריך ושעה ISO"2024-01-15T10:30:00-05:00"מעקב מתי המוצרים נוספו (זיהוי השקות חדשות)
updated_atתאריך ושעה ISO"2025-03-01T08:00:00-05:00"זיהוי שינויים עדכניים בקטלוג
published_atתאריך ושעה ISO"2024-01-16T00:00:00-05:00"לדעת מתי המוצרים עלו לחנות
tagsמערך מחרוזות["organic", "women", "straight-leg"]ניתוח תגיות/מילות מפתח ל‑SEO, סיווג וזיהוי מגמות
variantsמערך אובייקטים(ראו שדות וריאנט בהמשך)מחיר, SKU וזמינות לכל וריאנט
imagesמערך אובייקטים(ראו שדות תמונה בהמשך)כתובות תמונה לקטלוגים ולניתוח חזותי
optionsמערך אובייקטים[{"name": "Size", "values": ["S","M","L"]}]הבנת תצורת המוצר (מידה, צבע, חומר)

שדות ברמת וריאנט (מקוננים תחת כל מוצר)

שדהסוג נתוניםדוגמהשימוש
idמספר שלם987654321מזהה וריאנט ייחודי
titleמחרוזת"32 / Blue"שם התצוגה של הווריאנט
skuמחרוזת"HD-BLU-32"התאמת SKU למערכות מלאי
priceמחרוזת"185.00"מעקב מחירים (שימו לב: זו מחרוזת, צריך להמיר ל‑float לחישובים)
compare_at_priceמחרוזת או null"200.00"המחיר המקורי — חיוני למעקב אחר הנחות
availableבוליאניtrueזמינות במלאי (האינדיקטור הציבורי היחיד למלאי)
weightמספר עשרוני1.2ניתוח שילוח/לוגיסטיקה
option1, option2, option3מחרוזת"32", "Blue", nullערכי האפשרויות הבודדות
created_at, updated_atתאריך ושעה ISOמעקב שינויים ברמת וריאנט

שדות ברמת תמונה

שדהסוג נתוניםדוגמהשימוש
idמספר שלם111222333מזהה תמונה ייחודי
srcמחרוזת (URL)"https://cdn.shopify.com/..."קישור ישיר להורדת התמונה
altמחרוזת או null"Front view of jeans"טקסט חלופי של התמונה לצורכי נגישות
positionמספר שלם1סדר הופעת התמונות
width, heightמספר שלם2048, 2048ממדי התמונה

מה לא נמצא בנקודת הקצה הציבורית

נקודת כשל חשובה: inventory_quantity לא זמין בתגובות הציבוריות של /products.json. השדה הזה הוסר מנקודות קצה ציבוריות בפורמט JSON בדצמבר 2017 מסיבות אבטחה. האינדיקטור היחיד למלאי שתקבלו הוא השדה הבוליאני available בכל וריאנט (true או false). כדי לגשת לכמות מלאי אמיתית צריך להשתמש ב‑Admin API המאומת, עם אישורי בעל החנות.

לפני שכותבים את קוד הגרידה, עברו על הטבלה הזו והחליטו אילו שדות חשובים לכם. אם אתם עושים מעקב מחירים, תצטרכו את variants[].price, את variants[].compare_at_price ואת variants[].available. אם אתם עושים יצירת לידים, התמקדו ב‑vendor, ב‑product_type וב‑tags. סננו בהתאם — ה‑CSV שלכם יהיה הרבה יותר נקי.

מעבר ל‑products.json: קולקציות, מטא ונקודות קצה נוספות של Shopify

אף מדריך מתחרה לא מזכיר את הנקודות האלה. הן חיוניות לעבודת מודיעין תחרותי רצינית.

/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}

רוצים להבין איך מתחרה מארגן את הקטלוג שלו? זו הנקודה המתאימה.

/collections/{handle}/products.json — מוצרים לפי קטגוריה

מחזיר מוצרים מסוננים לפי קולקציה מסוימת. זהו אותו מבנה JSON כמו ב‑/products.json, אבל מוגבל לקטגוריה אחת. זה קריטי לגרידה ברמת קטגוריה — למשל אם רוצים לעקוב רק אחרי הקולקציה "Sale" או "New Arrivals" של מתחרה.

/meta.json — מטא־נתונים של החנות

מחזיר שם חנות, תיאור, מטבע, מדינה — והחלק המעניין — published_products_count. המספר הזה מאפשר לחשב מראש בדיוק כמה עמודי pagination תצטרכו: ceil(published_products_count / 250). כך כבר לא צריך להמשיך להעלות עמודים בצורה עיוורת עד שמתקבלת תשובה ריקה.

באיזו נקודת קצה כדאי להשתמש?

| מה רוצים לקבל | נקודת קצה | צריך אימות? | |---|---|---|---| | כל המוצרים (ציבורי) | /products.json | לא | | מוצרים בקטגוריה מסוימת | /collections/{handle}/products.json | לא | | מטא־נתונים של החנות + כמות מוצרים | /meta.json | לא | | כל הקולקציות (קטגוריות) | /collections.json | לא | | נתוני הזמנות/מכירות (רק לחנות שלך) | Admin API /orders.json | כן (API key) | | כמויות מלאי (רק לחנות שלך) | Admin API /inventory_levels.json | כן |

השאלה שחוזרת שוב ושוב בפורומים — "אפשר לגרד כמה יחידות מתחרה מכר?" — מקבלת תשובה קצרה: לא. לא מנקודות קצה ציבוריות. נתוני מכירות וכמויות מלאי דורשים את ה‑Admin API המאומת, כלומר צריך גישת בעלים לחנות. נקודות קצה ציבוריות נותנות רק נתוני קטלוג מוצרים.

shopify-data-access-methods.webp

איך לגרד Shopify עם Python: הגדרה שלב אחר שלב

  • רמת קושי: מתחילים
  • זמן נדרש: כ‑15 דקות (התקנה + גרידה ראשונה)
  • מה צריך: Python 3.11+, pip, טרמינל, וכתובת URL של חנות Shopify לגרידה

שלב 1: התקנת Python והספריות הדרושות

ודאו שמותקנת אצלכם גרסת Python 3.11 ומעלה (pandas 3.0.x דורש זאת). לאחר מכן התקינו את שתי הספריות שנצטרך:

1pip install requests pandas

לייצוא ל‑Excel, תצטרכו גם:

1pip install openpyxl

בראש הסקריפט הוסיפו את הייבוא הבא:

1import requests
2import pandas as pd
3import time
4import random
5import json

לא אמורות להופיע שגיאות ייבוא כשתריצו את הסקריפט. אם pandas זורקת שגיאת גרסה, שדרגו ל‑Python 3.12.

שלב 2: שליפת נתוני מוצרים מ‑/products.json

הנה פונקציה בסיסית שלוקחת כתובת חנות, פונה לנקודת הקצה ומחזירה 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, ולכן הגדרה מפורשת של הערך הזה מפחיתה את מספר הבקשות עד פי 8.
  • כותרת User-Agent: תמיד הגדירו אחת ריאליסטית. בקשות בלי User-Agent נוטות יותר להפעיל את מנגנוני האנטי‑בוט של Shopify.
  • timeout=30: אל תיתנו לבקשה אחת להיתקע לנצח.

בדקו את זה מול חנות מוכרת:

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 כדי לגרד את כל המוצרים

בקשה אחת מחזירה לכל היותר 250 מוצרים. לרוב החנויות יש יותר מזה (ל‑Allbirds יש 1,420+). לכן צריך לעבור בלולאה בין עמודים עד שמתקבלת תשובה ריקה.

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 אקראי עוזר להישאר מתחת למגבלת הקצב הלא רשמית של Shopify — בערך 2 בקשות לשנייה.

טיפ מקצועי: אם שלפתם קודם את /meta.json, כבר יש לכם את מספר המוצרים הכולל, ואפשר לחשב בדיוק כמה עמודים צריך: pages = ceil(product_count / 250). כך נמנעים מהדפוס של "עוד בקשה ריקה אחת בסוף".

שלב 4: ניתוח ובחירת השדות שאתם צריכים

עכשיו, כשיש לכם את כל המוצרים כרשימת מילונים ב‑Python, אפשר לחלץ רק את השדות שרלוונטיים לכם. הנה דוגמה שמושכת את השדות הנפוצים ביותר למעקב מחירים:

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

כך מתקבלת שורה אחת לכל וריאנט — הפורמט הכי שימושי להשוואת מחירים, כי מוצר אחד כמו "Classic Blue Jeans" יכול להכיל 12 וריאנטים (6 מידות × 2 צבעים), ולכל אחד מחיר ומצב זמינות משלו.

ייצוא נתוני Shopify שנגרדו ל‑CSV ו‑Excel עם pandas

כל מדריך אחר לגרידת Shopify זורק JSON גולמי לקובץ ומסיים שם. זה אולי מספיק למפתחים. פחות מועיל לאנליסט באיקומרס שצריך גיליון נתונים עד יום שישי.

הבעיה היא שה‑JSON של Shopify מקונן. מוצר אחד יכול לכלול תריסר וריאנטים, ולכל וריאנט מחיר, SKU וזמינות משלו. כדי להפוך את זה לשורות ועמודות צריך קצת עבודה עם pandas.

שטיחה של JSON מקונן לטבלה נקייה

יש שתי גישות, בהתאם לצורך שלכם:

אפשרות א: שורה אחת לכל וריאנט (הכי טוב למעקב מחירים ומלאי)

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 שורות.

אפשרות ב: שורה אחת לכל מוצר כסיכום (הכי טוב לסקירה כללית של הקטלוג)

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

ייצוא ל‑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, אבל בכנות — לרוב המקרים, ייצוא ל‑CSV והעלאה ל‑Google Drive הם פתרון מהיר ופשוט יותר.

גרידת Shopify מוכנה לפרודקשן: מגבלות קצב, ניסיונות חוזרים והתחמקות מחסימות

הסקריפט הבסיסי עובד מצוין בחנויות קטנות. אבל כשמגרדים חנות עם יותר מ‑5,000 מוצרים, או כמה חנויות ברצף? שם מתחילות הבעיות.

איך Shopify מתנהגת מבחינת מגבלות קצב וחסימות

לנקודות הקצה הציבוריות של JSON ב‑Shopify אין מגבלות קצב מתועדות רשמית (בניגוד למודל leaky bucket של ה‑Admin API), אבל בדיקות בפועל מראות:

  • קצב בטוח: בערך 2 בקשות לשנייה לכל חנות
  • תקרה רכה: כ‑40 בקשות בדקה לפני שמתחיל throttling
  • HTTP 429: "Too Many Requests" — תשובת מגבלת הקצב הסטנדרטית
  • HTTP 430: קוד ייעודי ל‑Shopify שמצביע על חסימה ברמת אבטחה, לא רק מגבלת קצב
  • HTTP 403 או הפניה ל‑CAPTCHA: בחלק מהחנויות עם הגנת Cloudflare נוספת

בקשות שמגיעות מתשתיות ענן משותפות (AWS Lambda, Google Cloud Run) נוטות במיוחד להיחסם, כי טווחי ה‑IP האלה מזוהים עם שיעורי שימוש לרעה גבוהים.

טכניקות לגרידת Shopify בצורה אמינה

זו ההתקדמות מ‑"עובד על המחשב שלי" ל‑"עובד בפרודקשן":

רמהטכניקהאמינות
בסיסיתrequests.get() + ?page=נשבר בקטלוגים גדולים, עלול להיחסם
בינוניתrequests.Session() + ?limit=250 + time.sleep(1) + retry על 429עובד ברוב החנויות
מתקדמת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.5 שניות → 1 שנייה → 2 שניות → 4 שניות → 8 שניות בין ניסיונות חוזרים. שימוש חוזר ב‑Session (requests.Session()) גם מעניק pooling של חיבורים, מה שמפחית overhead כשמבצעים כמה בקשות לאותו דומיין.

סיבוב User-Agent: אם אתם מגרדים כמה חנויות, רצוי להחליף בין 3–5 מחרוזות User-Agent ריאליסטיות של דפדפנים. זה לא עניין של הטעיה — זה פשוט מונע מכם להיראות כמו בוט ששולח בדיוק אותן כותרות בכל בקשה.

סקריפט Python מלא לגרידת Shopify עם ייצוא ל‑CSV

הנה הסקריפט המלא, מוכן להעתקה ולהדבקה, שמחבר את כל מה שראינו עד עכשיו. הוא כולל בערך 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+ שורות (שורה לכל וריאנט). הפלט בטרמינל ייראה בערך כך:

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: גרידת Shopify בשתי קליקים עם Thunderbit (חלופה ללא קוד)

לא כולם רוצים להתקין Python, לפתור שגיאות ייבוא או לתחזק סקריפט גרידה. עבור איש מכירות שצריך מחירי מתחרים עד מחר בבוקר, Python הוא פשוט יותר מדי.

לכן בנינו את — web scraper מבוסס AI שעובד כתוסף Chrome. בלי קוד, בלי מפתחות API, בלי צורך בהגדרת סביבה.

איך Thunderbit מגרד חנויות Shopify

ל‑Thunderbit יש תבנית Shopify Scraper ייעודית ומוגדרת מראש לעמודי מוצר ב‑Shopify. מתקינים את , נכנסים לחנות Shopify ולוחצים "Scrape". התבנית מחלצת אוטומטית שמות מוצרים, תיאורים, מחירים, פרטי וריאנטים, תמונות ומידע על ספקים.

בחנויות שבהן התבנית לא תואמת בצורה מושלמת (תבניות מותאמות אישית, פריסה חריגה), יכולת AI Suggest Fields של Thunderbit קוראת את הדף ומייצרת שמות עמודות אוטומטית. אפשר להתאים את זה — לשנות שמות עמודות, להוסיף שדות, ולכתוב הוראות כמו "לחלץ רק מוצרים עם compare_at_price מוגדר."

כמה יכולות שממפות ישירות למה שהסקריפט ב‑Python עושה:

  • גרידת תתי‑עמודים: נכנסת אוטומטית לכל עמוד מוצר ומעשירה את הטבלה בתיאורים מלאים, ביקורות או פרטי וריאנטים — בדיוק כמו שהסקריפט שלנו עושה דרך מעבר בין עמודים, אבל בלי קוד.
  • pagination אוטומטי: מטפל בעמודים עם לחיצה או בגלילה אינסופית בלי צורך בהגדרה.
  • גרידה מתוזמנת: אפשר להגדיר משימות חוזרות (למשל "כל יום שני ב‑9 בבוקר") למעקב מחירים שוטף — בלי cron job ובלי שרת.
  • ייצוא חינמי ל‑CSV, Excel, Google Sheets, Airtable או Notion בכל התוכניות.

סקריפט Python מול Thunderbit: השוואה כנה

גורםסקריפט PythonThunderbit (ללא קוד)
זמן התקנה15–60 דק' (סביבה + קוד)כ‑2 דק' (התקנת תוסף Chrome)
צריך קוד?כן (Python)לא
התאמה אישיתבלתי מוגבלתשדות מוצעים ב‑AI + פרומפטים מותאמים
טיפול ב‑paginationצריך לכתוב ידניתאוטומטי
פורמטי ייצואצריך לממש לבד (CSV/Excel)CSV, Excel, Google Sheets, Airtable, Notion (חינם)
הרצות מתוזמנותcron + hostingמתזמן מובנה
טיפול במגבלות קצבצריך לכתוב retries/backoffמטופל אוטומטית
הכי מתאים למפתחים, צינורות נתונים גדוליםמשתמשים עסקיים, חילוץ מהיר, ניטור חוזר

בחרו ב‑Python כשאתם צריכים שליטה מלאה או משתלבים בצינור נתונים רחב יותר. בחרו ב‑Thunderbit כשאתם צריכים נתונים מהר ולא רוצים לתחזק קוד. לעיון מעמיק יותר ב‑, כתבנו מדריך נפרד בנושא.

python-vs-thunderbit-comparison.webp

טיפים ושיטות עבודה מומלצות לגרידת חנויות Shopify

אלו תקפים בלי קשר לכלי שבו תבחרו:

  • תמיד השתמשו ב‑?limit=250 כדי לצמצם את מספר הבקשות. ברירת המחדל של 30 לעמוד פירושה פי 8 יותר בקשות לאותו מידע.
  • כבדו את החנות: הוסיפו השהייה של 1–2 שניות בין בקשות. הפגזת שרת בבקשות מהירות היא גם לא נימוסית וגם מעלה את הסיכוי להיחסם.
  • בדקו קודם את robots.txt: כברירת מחדל, Shopify לא חוסמת את /products.json ב‑robots.txt. אבל חלק מהחנויות מוסיפות חוקים מותאמים, אז כדאי לוודא לפני גרידה בקנה מידה גדול.
  • שמרו קודם את ה‑JSON הגולמי מקומית, ורק אחר כך תעבדו אותו. אם ההיגיון של הניתוח ישתנה בהמשך, לא תצטרכו לגרד מחדש. json.dump(all_products, open("raw_data.json", "w")) פשוט לפני השטחה יחסוך כאב ראש.
  • בצעו deduplication לפי product.id: במקרי קצה של pagination עלולות להופיע כפילויות בגבולות בין עמודים. df.drop_duplicates(subset=["product_id", "variant_id"]) יפתור את זה מהר.
  • המירו price ל‑float לפני חישובים. Shopify מחזירה מחירים כמחרוזות ("185.00"), לא כמספרים.
  • עקבו אחרי שינויים בנקודת הקצה: אמנם /products.json יציבה כבר שנים, אבל תיאורטית Shopify יכולה להגביל אותה. אם הסקריפט פתאום מתחיל להחזיר 404, בדקו קודם את החנות ידנית.

לעוד מידע על בניית סקרייפרים יציבים, ראו את המדריך שלנו על .

שיקולים משפטיים ואתיים בגרידת Shopify

קטע קצר, אבל חשוב.

נקודת הקצה /products.json מגישה נתוני מוצרים הזמינים לציבור — אותו מידע שכל מבקר רואה כשגולשים בחנות. בתנאי השירות של Shopify יש ניסוח לגבי אי‑שימוש ב"אמצעים אוטומטיים" כדי לגשת ל"שירותים", אבל הניסוח הזה מתייחס לפלטפורמה עצמה (לוח הניהול, ה‑checkout), לא לנתוני חנות ציבוריים. נכון לאפריל 2026, לא הוגשו תביעות גרידה ספציפיות ל‑Shopify.

תקדימים משפטיים חשובים תומכים בגרידת נתונים ציבוריים: hiQ v. LinkedIn קבע שגרידת מידע הזמין לציבור אינה מפרה את ה‑CFAA, ו‑Meta v. Bright Data (2024) קבע שהגבלות TOS חלות רק כאשר המשתמש מחובר.

שיטות עבודה מומלצות:

  • גרדו רק נתוני מוצרים ציבוריים
  • אל תגרדו נתונים אישיים או נתוני לקוחות
  • כבדו robots.txt ומגבלות קצב
  • עמדו ב‑GDPR/CCPA אם אתם מטפלים בנתונים אישיים כלשהם (נתוני קטלוג מוצרים אינם אישיים)
  • הזדהו עם מחרוזת User-Agent ברורה
  • גרידה של חנות Shopify שלכם דרך ה‑Admin API תמיד תקינה

לקריאה מעמיקה יותר, ראו את הפוסט שלנו על .

מסקנות וסיכום עיקרי

נקודת הקצה הציבורית /products.json של Shopify הופכת חילוץ נתוני איקומרס לפשוט מאוד. התהליך הוא: מוסיפים /products.json → שולפים עם Python → עוברים על pagination עם ?limit=250&page= → משטחים עם pandas → מייצאים ל‑CSV או Excel.

מה שהמדריך הזה מכסה ושאחרים לא:

  • פירוט מלא של שדות: יודעים בדיוק אילו נתונים זמינים (40+ שדות על פני מוצרים, וריאנטים ותמונות) לפני כתיבת שורת קוד אחת
  • נקודות קצה נוספות: /collections.json ו‑/meta.json נותנות לכם מודיעין ברמת קטגוריה ומטא־נתוני חנות שאף מדריך מתחרה לא מכסה
  • טכניקות מוכנות לפרודקשן: שימוש חוזר ב‑Session, exponential backoff, כותרות User-Agent ו‑?limit=250 כדי להתמודד עם מגבלות קצב אמיתיות
  • ייצוא נכון ל‑CSV/Excel: נתונים שטוחים ברמת וריאנט עם pandas, לא רק dump גולמי של JSON
  • חלופה ללא קוד: למי שמעדיף מהירות על פני גמישות קוד

למשיכות נתוני Shopify חד‑פעמיות או חוזרות בלי קוד, נסו את — תבנית Shopify Scraper מטפלת בהכול, מה‑pagination ועד הייצוא. עבור צינורות נתונים מותאמים אישית או גרידה בקנה מידה רחב על פני חנויות רבות, סקריפט ה‑Python במדריך הזה נותן לכם שליטה מלאה.

בדקו את להדרכות וידאו, או עיינו במדריכים שלנו על ועל לטכניקות קשורות.

נסו את Thunderbit לגרידת Shopify

שאלות נפוצות

האם אפשר לגרד כל חנות Shopify עם products.json?

רוב חנויות Shopify חושפות את הנקודה הזו כברירת מחדל — בבדיקות, בערך 71% החזירו JSON תקין. חלק מהחנויות עם תצורות מותאמות אישית או שכבות אבטחה נוספות (Cloudflare, תצורות headless) עלולות להחזיר 404 או לחסום את הבקשה. בדיקה מהירה: נכנסים ל‑{store-url}/products.json בדפדפן. אם רואים JSON, הכול תקין.

האם חוקי לגרד חנויות Shopify?

נתוני מוצרים ציבוריים (מחירים, כותרות, תמונות, תיאורים) בדרך כלל נגישים, ותקדימים משפטיים כמו hiQ v. LinkedIn תומכים בגרידה של מידע ציבורי. עם זאת, תמיד כדאי לבדוק את תנאי השירות של החנות הספציפית ואת החוקים המקומיים. אל תגרדו נתונים אישיים או נתוני לקוחות, וכבדו מגבלות קצב.

כמה מוצרים אפשר לגרד מחנות Shopify?

אין מגבלה קשיחה על הכמות הכוללת. pagination עם ?limit=250&page= מאפשר למשוך את כל הקטלוג. בחנויות גדולות מאוד (25,000+ מוצרים), כדאי להשתמש ב‑Session reuse ובהשהיות כדי להימנע ממגבלות קצב. נקודת הקצה /meta.json יכולה להגיד לכם מראש מה מספר המוצרים המדויק, כך שתדעו כמה עמודים לצפות.

מה ההבדל בין products.json לבין Shopify Admin API?

/products.json היא נקודת קצה ציבורית — בלי אימות, נתוני מוצר לקריאה בלבד, זמינים לכל אחד. ה‑Admin API דורש אסימוני גישה של בעל החנות ומספק הזמנות, כמויות מלאי, נתוני לקוחות והרשאת כתיבה. אם אתם צריכים נתוני מכירות או ספירות מלאי אמיתיות, תצטרכו גישה ל‑Admin API (כלומר להיות בעלי החנות או לפעול בהרשאתם).

אפשר לגרד Shopify בלי Python?

בהחלט. כלים כמו מאפשרים לגרד חנויות Shopify מתוך תוסף Chrome בלי לכתוב קוד. הוא מטפל ב‑pagination אוטומטית ומייצא ישירות ל‑CSV, Excel, Google Sheets, Airtable או Notion. עבור מפתחים שמעדיפים שפות אחרות, אותה נקודת קצה /products.json עובדת גם עם JavaScript, Ruby, Go — כל שפה שיכולה לבצע בקשות HTTP ולנתח JSON.

למידע נוסף

תוכן עניינים

נסה את Thunderbit

חלץ לידים ונתונים אחרים ב-2 קליקים בלבד. מופעל על ידי AI.

קבל את Thunderbit זה בחינם
חלץ נתונים באמצעות AI
העבר בקלות נתונים ל-Google Sheets, Airtable או Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week