用 Python 自動化市場研究:抓取 Shopify 資料

最後更新於 April 16, 2026
用 Python 自動化市場研究:抓取 Shopify 資料

Shopify 的 /products.json 端點可以說是電商資料圈裡大家都知道的「神兵利器」。只要在任何 Shopify 商店網址後面接上它,就能直接拿到結構化 JSON——不用 API 金鑰、不用驗證,也不用在一層又一層的 HTML 裡東翻西找。

我在 Thunderbit 官方網站 團隊工作,所以平常很常在想大家要怎麼從網路上擷取資料。Shopify 抓取這件事也常被提到——像是銷售團隊追蹤競品價格、電商營運人員比較商品目錄、採購人員找新供應商。Shopify 目前有 482 萬家活躍商家,而且平台大約佔美國電商市場的 30%,能抓到的商品資料量真的很驚人。

這篇指南會完整帶你走一遍流程:端點會回傳什麼、怎麼分頁抓取數千個商品、如何在不被封鎖的前提下處理速率限制,以及怎麼用 pandas 把 Shopify 的巢狀 JSON 攤平成乾淨的 CSV 或 Excel 檔。我也會介紹其他文章比較少提到的端點(/collections.json/meta.json),最後再提供一個免寫程式的替代方案,給想直接跳過 Python 的人。

Shopify 的 /products.json 端點是什麼?為什麼它讓抓取變得這麼簡單?

每個 Shopify 商店都有一個公開端點 {store-url}/products.json,會回傳結構化的商品資料。沒有 API 金鑰、沒有 OAuth、也不用任何驗證。你只要把 /products.json 接到商店網址後面,就能拿到整個商品目錄的 JSON 陣列。

你現在就可以自己試試看:在瀏覽器打開 allbirds.com/products.jsonzoologistperfumes.com/products.json。你會看到乾淨、結構清楚的 JSON,裡面包含商品標題、價格、變體、圖片、標籤等資訊。

跟另一種做法比起來差異就很明顯:解析 Shopify 的 HTML 主題頁面,通常結構一層包一層、不同商店的格式也不一樣,而且商家只要一更新主題,整個結構就可能變掉。你要處理的會是這種東西:

HTML 做法(很痛苦):

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

JSON 做法(很乾淨):

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

在一致性、穩定性和解析難度上,JSON 都明顯更有優勢。這個端點也支援兩個重要查詢參數——?limit=(每頁最多 250 筆商品,預設是 30)與 ?page=(分頁)——後面的範例會大量用到。

要注意的是:這是 公開的商店前台端點,不是 Shopify Admin API。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 看看結果。

為什麼要用 Python 抓 Shopify?常見商業應用場景

為什麼值得做?因為投資報酬率很高。81% 的美國零售商現在都會用自動化價格抓取來做競爭情報分析,遠高於 2020 年的 34%。研究也顯示,價格策略只要改善 1%,平均就能帶來 11.1% 的獲利成長。這些資料真的很有價值。

以下是我最常看到的應用情境:

應用場景受益對象你能得到什麼
競品價格監控電商營運團隊追蹤競品目錄中的價格變動、折扣與比價價格
商品研究與採購採購/商品企劃比較商品特色、變體、材質與庫存可得性
名單開發業務團隊從商店目錄擷取供應商名稱、品牌資料與聯絡資訊
市場與品類分析行銷團隊了解商品組合、標籤、集合分類結構與定位
庫存與供應狀態追蹤供應鏈團隊監控變體層級的庫存狀態(available: true/false)
新品偵測產品團隊追蹤 created_at 時間戳,找出競品新品上架時間

Python 是做這件事的自然選擇。69.6% 的爬蟲開發者都把 Python 當作主要語言,而 requests 負責 HTTP、pandas 處理資料、httpx 可以做非同步,讓你能在 80 行以內的程式碼中,從「我有一個網址」一路做到「我有一份試算表」。

完整的 products.json 欄位參考:每個欄位都幫你拆解好

很多教學只會展示 titleidhandle,然後就草草帶過。但 Shopify 的 JSON 回應其實包含 40 多個跨商品、變體、圖片與選項的欄位。先了解有哪些欄位,再開始寫抓取程式,能省下之後重抓的麻煩。

我整理這份參考表,是根據 2026 年 4 月 16 日實際抓取的 /products.json 回應。只要端點有開放,所有商店的結構都一樣。

商品層級欄位

欄位資料類型範例值商業用途
id整數123456789商品唯一識別碼,用於去重
title字串"Classic Blue Jeans"商品名稱,用於目錄與比對
handle字串"classic-blue-jeans"URL slug,可組成商品頁連結 {store}/products/{handle}
body_html字串(HTML)或 null

Our best-selling...

商品描述,可用於內容分析與 SEO 研究
vendor字串"Hiut Denim"品牌/供應商名稱,用於開發名單或採購
product_type字串"Jeans"品類分類,用於市場分析
created_atISO 日期時間"2024-01-15T10:30:00-05:00"追蹤商品新增時間(新品偵測)
updated_atISO 日期時間"2025-03-01T08:00:00-05:00"偵測目錄近期變動
published_atISO 日期時間"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_atISO 日期時間變體層級變更追蹤

圖片層級欄位

欄位資料類型範例用途
id整數111222333圖片唯一識別碼
src字串(URL)"https://cdn.shopify.com/..."圖片直接下載連結
alt字串或 null"Front view of jeans"圖片替代文字,可用於無障礙分析
position整數1圖片排序
width, height整數2048, 2048圖片尺寸

公開端點沒有的欄位

有一個很重要的坑:公開的 /products.json 回應中沒有 inventory_quantity 這個欄位在 2017 年 12 月就從公開 JSON 端點移除了,原因是安全性考量。你能拿到的唯一庫存指標,是每個變體上的布林欄位 availabletruefalse)。如果你要真正的庫存數量,就必須使用有驗證的 Admin API,並且具備商店擁有者權限。

在寫程式之前,先看過這張表,決定哪些欄位跟你的需求相關。如果你是做價格監控,就需要 variants[].pricevariants[].compare_at_pricevariants[].available。如果你是做名單開發,就聚焦在 vendorproduct_typetags。先過濾再輸出,CSV 會乾淨很多。

不只 products.json:Collections、Meta 與其他 Shopify 端點

很少有競品教學會提到這些端點,但如果你在做比較嚴謹的競爭情報分析,它們非常重要。

/collections.json — 商店所有分類

會回傳商店內所有集合(分類),包含標題、handle、描述和商品數量。我在 zoologistperfumes.com、allbirds.com 與 gymshark.com 都測過,全部都能正常回傳 JSON。

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

想了解競品是怎麼整理商品目錄的?就看這個端點。

/collections/{handle}/products.json — 依分類取得商品

這個端點會回傳某個特定集合底下的商品,JSON 結構和 /products.json 一樣,但只限於單一分類。這對分類層級的抓取很重要——例如你只想監控競品的「Sale」或「New Arrivals」分類。

/meta.json — 商店層級中繼資料

會回傳商店名稱、描述、幣別、國家,還有最重要的 published_products_count。有了這個數字,你就能先算出需要幾頁分頁: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

用 Python 抓 Shopify:一步一步設定教學

  • 難度: 初學者
  • 所需時間: 約 15 分鐘(設定 + 第一次抓取)
  • 你需要準備: Python 3.11 以上、pip、終端機,以及一個要抓取的 Shopify 商店網址

步驟 1:安裝 Python 與必要函式庫

先確認你已安裝 Python 3.11 以上版本(pandas 3.0.x 需要)。接著安裝我們需要的兩個套件:

pip install requests pandas

如果要匯出 Excel,還需要:

pip install openpyxl

在程式最上方加入以下匯入:

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

執行時如果沒有 import 錯誤,就代表安裝正常。如果 pandas 出現版本錯誤,請升級到 Python 3.12。

步驟 2:從 /products.json 取得商品資料

下面是一個基本函式,輸入商店網址後,會向端點發送請求並回傳解析後的 JSON:

def fetch_products_page(store_url, page=1, limit=250):
    """從 Shopify 商店抓取單一頁商品資料。"""
    url = f"{store_url.rstrip('/')}/products.json"
    params = {"limit": limit, "page": page}
    headers = {
        "User-Agent": "Mozilla/5.0 (compatible; ProductResearch/1.0)"
    }
    
    response = requests.get(url, params=params, headers=headers, timeout=30)
    response.raise_for_status()
    return response.json().get("products", [])

幾個重點:

  • limit=250 是 Shopify 每頁允許的上限。預設只有 30,所以明確設定可以把請求數量最多減少 8 倍。
  • User-Agent 標頭:一定要設定一個像真實瀏覽器的字串。沒有 User-Agent 的請求,更容易觸發 Shopify 的防機器人機制。
  • timeout=30:避免單一請求卡住太久。

用一個已知商店測試看看:

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

你應該會看到像這樣的輸出:Fetched 250 products,以及第一個商品標題。

步驟 3:處理分頁,把所有商品都抓下來

單次請求最多只能拿到 250 個商品。很多商店都超過這個數量(Allbirds 就有 1,420+ 個)。你需要持續迴圈翻頁,直到拿到空回應。

def scrape_all_products(store_url, delay=1.0):
    """抓取 Shopify 商店的所有商品,並處理分頁。"""
    all_products = []
    page = 1
    
    while True:
        print(f"Fetching page {page}...")
        products = fetch_products_page(store_url, page=page, limit=250)
        
        if not products:
            print(f"No more products. Total: {len(all_products)}")
            break
        
        all_products.extend(products)
        print(f"  Got {len(products)} products (total so far: {len(all_products)})")
        page += 1
        
        # 禮貌一點:每次請求之間稍微等一下
        time.sleep(delay + random.uniform(0, 0.5))
    
    return all_products

products 回傳空陣列時,就代表已經抓到最後一頁。

time.sleep() 再加上隨機抖動,可以把請求頻率維持在 Shopify 大致可接受的非正式速率限制內(約每秒 2 次)。

小技巧:如果你先抓 /meta.json,就能知道總商品數,直接算出需要幾頁:pages = ceil(product_count / 250)。這樣就不會在最後多送一次空請求。

步驟 4:解析並挑選你需要的欄位

現在你已經拿到一個由字典組成的 Python list,接著只要擷取你關心的欄位即可。以下範例示範如何抓出最常見的價格監控欄位:

def extract_product_data(products):
    """從商品中擷取關鍵欄位,並將變體展平。"""
    rows = []
    for product in products:
        for variant in product.get("variants", []):
            rows.append({
                "product_id": product["id"],
                "title": product["title"],
                "handle": product["handle"],
                "vendor": product.get("vendor", ""),
                "product_type": product.get("product_type", ""),
                "tags": ", ".join(product.get("tags", [])),
                "created_at": product.get("created_at", ""),
                "variant_id": variant["id"],
                "variant_title": variant.get("title", ""),
                "sku": variant.get("sku", ""),
                "price": variant.get("price", ""),
                "compare_at_price": variant.get("compare_at_price", ""),
                "available": variant.get("available", ""),
                "image_url": product["images"][0]["src"] if product.get("images") else ""
            })
    return rows

這會建立一筆變體對應一列的資料格式——對價格比較最實用,因為像「Classic Blue Jeans」這類商品可能有 12 個變體(6 種尺寸 × 2 種顏色),每個變體都有自己的價格與可售狀態。

用 pandas 將抓取到的 Shopify 資料匯出成 CSV 與 Excel

其他 Shopify 抓取教學通常只會把原始 JSON 存成檔案就結束了。對開發者來說還行,對需要在週五前交出試算表的電商分析師來說,根本不夠。

問題在於:Shopify 的 JSON 是巢狀結構。一個商品可能包含十幾個變體,而每個變體都有自己的價格、SKU 和可售性。要把它攤平成列與欄,就需要借助 pandas。

把巢狀 JSON 攤平成乾淨表格

根據你的需求,可以有兩種做法:

方案 A:一個變體一列(最適合價格監控與庫存追蹤)

# 使用步驟 4 的 extract_product_data 函式
products = scrape_all_products("https://allbirds.com")
rows = extract_product_data(products)
df = pd.DataFrame(rows)

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

這會得到一張平面表格,每一列都是唯一的商品+變體組合。一個有 500 個商品、平均每個商品 4 個變體的商店,最後大約會產生 2,000 列的 DataFrame。

方案 B:一個商品一列的摘要表(最適合做目錄總覽)

def summarize_products(products):
    """每個商品一列,顯示各變體的最低/最高價格。"""
    rows = []
    for product in products:
        prices = [float(v["price"]) for v in product.get("variants", []) if v.get("price")]
        rows.append({
            "product_id": product["id"],
            "title": product["title"],
            "vendor": product.get("vendor", ""),
            "product_type": product.get("product_type", ""),
            "variant_count": len(product.get("variants", [])),
            "min_price": min(prices) if prices else None,
            "max_price": max(prices) if prices else None,
            "any_available": any(v.get("available", False) for v in product.get("variants", [])),
            "tags": ", ".join(product.get("tags", []))
        })
    return rows

匯出成 CSV、Excel 與 Google Sheets

# 匯出 CSV(使用 utf-8-sig,讓 Excel 能正確處理特殊字元)
df.to_csv("shopify_products.csv", index=False, encoding="utf-8-sig")

# 匯出 Excel(需要 openpyxl)
df.to_excel("shopify_products.xlsx", index=False, engine="openpyxl")

print("已匯出為 shopify_products.csv 和 shopify_products.xlsx")

如果要匯出到 Google Sheets,可以用 gspread 搭配 service account。不過老實說,對大多數情境而言,直接輸出 CSV 再上傳到 Google Drive 會更快也更簡單。

可上線使用的 Python 抓取:速率限制、重試與防封鎖

前面的基礎腳本抓小型商店沒問題。但如果你要抓 5,000+ 個商品的商店,或是連續抓多個商店,問題就會開始冒出來。

了解 Shopify 的速率限制與封鎖機制

Shopify 的公開 JSON 端點沒有像 Admin API 那樣明確文件化的速率限制(Admin API 採用的是漏桶模型),但實際測試會發現:

  • 安全速度:每個商店約每秒 2 個請求
  • 軟性上限:每分鐘約 40 個請求後,開始可能出現節流
  • 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) + 429 重試適用於多數商店
高階非同步 httpx + 輪換 User-Agent + 指數退避可用於正式環境,能擴展到 1 萬+ 商品

進階方案(多數使用者都適合):

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

def create_session():
    """建立一個具備自動重試機制的 requests session。"""
    session = requests.Session()
    retries = Retry(
        total=5,
        backoff_factor=1,  # sleep: 0.5s, 1s, 2s, 4s, 8s
        status_forcelist=[429, 430, 500, 502, 503, 504],
        respect_retry_after_header=True
    )
    session.mount("https://", HTTPAdapter(max_retries=retries))
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
    })
    return session

Retry 設定會在遇到 429 時自動做指數退避。backoff_factor=1 代表重試間隔會依序是 0.5 秒 → 1 秒 → 2 秒 → 4 秒 → 8 秒。使用 requests.Session() 重複連線,也能透過連線池降低同一網域多次請求的額外成本。

User-Agent 輪換:如果你要抓多個商店,建議輪流使用 3–5 組真實的瀏覽器 User-Agent 字串。這不是為了欺騙,而是避免每次請求都送出一模一樣的標頭,看起來太像機器人。

完整可執行的 Python 腳本:抓取 Shopify 並輸出 CSV

以下是完整、可直接複製貼上的腳本,把前面的內容全部整合在一起。實際程式碼大約 75 行(加上註解),我已經拿 Allbirds(1,420 個商品)、ColourPop(2,000+ 商品)以及 Zoologist Perfumes(小型目錄)測試過。

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


def create_session():
    """建立具備速率限制重試邏輯的 session。"""
    session = requests.Session()
    retries = Retry(
        total=5,
        backoff_factor=1,
        status_forcelist=[429, 430, 500, 502, 503, 504],
        respect_retry_after_header=True
    )
    session.mount("https://", HTTPAdapter(max_retries=retries))
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                      "AppleWebKit/537.36 (KHTML, like Gecko) "
                      "Chrome/125.0.0.0 Safari/537.36"
    })
    return session


def scrape_shopify(store_url, delay=1.0):
    """透過 /products.json 抓取 Shopify 商店的所有商品。"""
    session = create_session()
    all_products = []
    page = 1
    base_url = f"{store_url.rstrip('/')}/products.json"

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

        if not products:
            break

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

    return all_products


def flatten_to_variants(products):
    """把巢狀商品 JSON 攤平成每個變體一列。"""
    rows = []
    for p in products:
        base = {
            "product_id": p["id"],
            "title": p["title"],
            "handle": p["handle"],
            "vendor": p.get("vendor", ""),
            "product_type": p.get("product_type", ""),
            "tags": ", ".join(p.get("tags", [])),
            "created_at": p.get("created_at", ""),
            "updated_at": p.get("updated_at", ""),
            "image_url": p["images"][0]["src"] if p.get("images") else "",
        }
        for v in p.get("variants", []):
            row = {**base}
            row["variant_id"] = v["id"]
            row["variant_title"] = v.get("title", "")
            row["sku"] = v.get("sku", "")
            row["price"] = v.get("price", "")
            row["compare_at_price"] = v.get("compare_at_price", "")
            row["available"] = v.get("available", "")
            rows.append(row)
    return rows


if __name__ == "__main__":
    STORE_URL = "https://allbirds.com"  # 改成你的目標商店
    OUTPUT_CSV = "shopify_products.csv"
    OUTPUT_EXCEL = "shopify_products.xlsx"

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

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

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

python scrape_shopify.py 執行即可。以 Allbirds 為例,整個過程大約需要 45 秒,最後會產生一份約 5,000+ 列的 CSV(每個變體一列)。終端機輸出大概會像這樣:

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

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

Exported to shopify_products.csv and shopify_products.xlsx

不想寫 Python?用 Thunderbit 2 步驟抓 Shopify(免寫程式替代方案)

不是每個人都想安裝 Python、處理 import 錯誤,或維護抓取腳本。對於明天早上就要競品價格資料的業務來說,Python 可能太重了。

這也是我們打造 Thunderbit 官方網站 的原因——一款以 Chrome 擴充功能形式運作的 AI 網頁爬蟲。免寫程式、免 API 金鑰,也不用設定環境。

試用 Thunderbit Chrome 擴充功能

Thunderbit 如何抓 Shopify 商店

Thunderbit 內建專為 Shopify 商品頁設計的 Shopify 爬蟲範本。你只要安裝 Thunderbit Chrome 擴充功能下載頁,打開 Shopify 商店,然後按下「Scrape」。這個範本會自動擷取商品名稱、描述、價格、變體細節、圖片與供應商資訊。

如果某些商店的版型不完全符合範本(例如自訂主題、特殊排版),Thunderbit 的 AI Suggest Fields 功能會直接讀取頁面,並自動產生欄位名稱。你還可以自己調整,例如重新命名欄位、增加欄位,或寫入像「只抓 compare_at_price 有值的商品」這類指令。

以下幾個功能,和前面 Python 程式能做的事情幾乎一樣:

  • 子頁面抓取:自動前往每個商品詳細頁,補充完整描述、評論或變體細節——等同於我們在 Python 程式裡逐頁抓取,但完全不用寫程式。
  • 自動分頁:可自動處理點擊式分頁和無限捲動,不需要額外設定。
  • 排程抓取:可設定週期性任務(例如「每週一上午 9 點」)持續監控價格,不需要 cron job 或伺服器。
  • 免費匯出:所有方案都可免費匯出到 CSV、Excel、Google Sheets、Airtable 或 Notion。

Python 腳本 vs. Thunderbit:誠實比較

比較項目Python 腳本Thunderbit(免寫程式)
設定時間15–60 分鐘(環境 + 程式碼)約 2 分鐘(安裝 Chrome 擴充功能)
需要寫程式嗎需要(Python)不需要
客製化能力幾乎無上限AI 建議欄位 + 自訂提示詞
分頁處理需自行撰寫自動處理
匯出格式需自行程式化(CSV/Excel)CSV、Excel、Google Sheets、Airtable、Notion(免費)
排程執行需 cron job + 主機內建排程器
速率限制處理需自行實作重試/退避自動處理
最適合誰開發者、大規模資料流程商務使用者、快速擷取、持續監控

當你需要完整控制權,或要把資料整合進更大的資料管線時,用 Python。當你想快速拿到資料、不想維護程式時,用 Thunderbit。如果你想更深入了解 價格比較的網頁抓取,我們也另外寫了一篇專文。

python-vs-thunderbit-comparison.webp

抓 Shopify 商店的技巧與最佳實踐

不管你用什麼工具,下面這些原則都適用:

  • 一定要用 ?limit=250,把請求數降到最低。預設每頁 30 筆,代表同樣資料要多做 8 倍請求。
  • 尊重商店伺服器:每次請求間停 1–2 秒。瘋狂連打伺服器不只是壞習慣,也更容易被封鎖。
  • 先檢查 robots.txt:Shopify 預設的 robots.txt 不會擋 /products.json,但有些商店會加自訂規則,所以大量抓取前還是要確認一下。
  • 先把原始 JSON 存到本地,再進行處理。如果之後解析邏輯變了,就不用重新抓一次。先做個 json.dump(all_products, open("raw_data.json", "w")) 再展平,能省很多麻煩。
  • product.id 去重:分頁邊界偶爾可能出現重複商品,df.drop_duplicates(subset=["product_id", "variant_id"]) 可以快速清理。
  • 做數學運算前先把 price 轉成 float。Shopify 回傳的是字串(例如 "185.00"),不是數字。
  • 持續監控端點變動:雖然 /products.json 多年來都很穩定,但 Shopify 理論上仍可能調整限制。如果你的爬蟲突然 404,先手動檢查商店頁面。

如果你想了解更穩健的爬蟲設計,可以參考我們關於 網頁爬蟲工具最佳實踐 的指南。

抓 Shopify 時的法律與倫理考量

篇幅不長,但很重要。

/products.json 端點提供的是公開可見的商品資料——也就是任何訪客在商店前台都能看到的內容。Shopify 的服務條款雖然有提到不能用「自動化方式」存取「服務」,但這裡指的是平台本身(像是後台管理、結帳流程),不是公開前台資料。到 2026 年 4 月為止,尚未有針對 Shopify 公開資料抓取的專門訴訟。

已有一些重要判例支持公開資料抓取:hiQ v. LinkedIn 確立了抓取公開可存取資料不違反 CFAA,而 Meta v. Bright Data(2024)則指出,TOS 限制主要適用於使用者登入後的情況。

最佳做法:

  • 只抓取公開可見的商品資料
  • 不要抓個人或客戶資料
  • 遵守 robots.txt 與速率限制
  • 如果處理到任何個人資料,請遵守 GDPR/CCPA(商品目錄資料不屬於個資)
  • 使用清楚的 User-Agent 字串表明身分
  • 抓取自己商店的資料時,透過 Admin API 永遠是沒問題的

若你想更深入了解,可閱讀我們關於 網頁爬取的法律影響 的文章。

結論與重點整理

Shopify 的公開 /products.json 端點,讓電商資料擷取變成一件相對簡單的事。整體流程就是:在網址後加上 /products.json → 用 Python 取得資料 → 用 ?limit=250&page= 分頁 → 用 pandas 展平 → 匯出成 CSV 或 Excel。

這篇指南比其他教學更完整的地方包括:

  • 完整欄位參考:在寫任何程式碼前,就能清楚知道有哪些資料可用(涵蓋商品、變體與圖片的 40+ 欄位)
  • 額外端點/collections.json/meta.json 提供分類層級情報與商店中繼資料,這是其他教學少提到的
  • 可上線使用的技巧:session 重用、指數退避、User-Agent 標頭與 ?limit=250,用來應對真實環境中的速率限制
  • 正確的 CSV/Excel 匯出方式:使用 pandas 把變體層級資料攤平,而不是只丟一包原始 JSON
  • 免寫程式替代方案:對於偏好速度勝過程式彈性的使用者,推薦 Thunderbit

如果你只是要一次性或定期抓 Shopify 資料,又不想寫程式,可以試試 Thunderbit Chrome 擴充功能下載頁——內建的 Shopify 爬蟲範本可處理從分頁到匯出的所有流程。如果你要為多個商店建立客製化資料管線,或要大規模抓取,這篇文章中的 Python 腳本會給你完整控制權。

也歡迎到我們的 Thunderbit YouTube 頻道 看影片教學,或延伸閱讀我們關於 抓取 Amazon 商品將網站資料匯出到 Excel 的相關指南。

試用 Thunderbit 進行 Shopify 抓取 Get Started Free

常見問題

可以用 products.json 抓任何 Shopify 商店嗎?

大多數 Shopify 商店預設都會開放這個端點——根據測試,大約 71% 會回傳有效 JSON。有些啟用自訂設定或額外安全防護(例如 Cloudflare、無頭架構)的商店,可能會回 404 或直接擋掉請求。快速檢查方式:直接在瀏覽器打開 {store-url}/products.json。如果看得到 JSON,就代表可以抓。

抓 Shopify 商店是否合法?

公開商品資料(價格、標題、圖片、描述)通常是可取得的,而且像 hiQ v. LinkedIn 這類法律先例也支持抓取公開資訊。不過你還是應該查看該商店的服務條款以及當地法律。不要抓個人或客戶資料,並遵守速率限制。

一個 Shopify 商店最多可以抓多少商品?

總數沒有硬性上限。使用 ?limit=250&page= 分頁,就能把整個目錄都抓下來。若是超大型商店(25,000+ 商品),建議搭配 session 重用與延遲,避免觸發速率限制。/meta.json 端點可以事先告訴你確切商品數,方便你預估會有幾頁。

products.json 跟 Shopify Admin API 有什麼差別?

/products.json 是公開端點——不需要驗證、只提供唯讀商品資料、任何人都能存取。Admin API 則需要商店擁有者的存取權杖,會提供訂單、庫存數量、客戶資料,以及寫入權限。如果你需要銷售資料或實際庫存數量,就必須使用 Admin API(也就是你必須是商店擁有者,或得到對方授權)。

不用 Python 也能抓 Shopify 嗎?

當然可以。像 Thunderbit 官方網站 這類工具,就能透過 Chrome 擴充功能免寫程式抓取 Shopify 商店。它會自動處理分頁,並直接匯出到 CSV、Excel、Google Sheets、Airtable 或 Notion。若你是偏好其他語言的開發者,同樣的 /products.json 端點也能搭配 JavaScript、Ruby、Go——任何能送出 HTTP 請求並解析 JSON 的語言都可以。

延伸閱讀

Ke
Ke
Thunderbit 技術長|資深資料科學家與機器學習專家 Ke Shen 在機器學習與資料科學領域擁有近十年經驗,畢業於哥倫比亞大學,曾任 Walmart Labs 資深資料科學家。他精通 Python、R、Java 與統計學,且具備深受同儕認可的深厚專業,分享如何將複雜的 AI 演算法從理論落實到可投入生產的架構的實戰見解。

試用 Thunderbit

只要 2 次點擊,就能抓取潛在客戶與其他資料。由 AI 驅動。

取得 Thunderbit 免費
使用 AI 擷取資料
輕鬆將資料傳送到 Google Sheets、Airtable 或 Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week