Shopify 的 /products.json 端點可以說是電商資料圈裡大家都知道的「神兵利器」。只要在任何 Shopify 商店網址後面接上它,就能直接拿到結構化 JSON——不用 API 金鑰、不用驗證,也不用在一層又一層的 HTML 裡東翻西找。
我在 團隊工作,所以平常很常在想大家要怎麼從網路上擷取資料。Shopify 抓取這件事也常被提到——像是銷售團隊追蹤競品價格、電商營運人員比較商品目錄、採購人員找新供應商。Shopify 目前有 ,而且平台大約佔美國電商市場的 ,能抓到的商品資料量真的很驚人。
這篇指南會完整帶你走一遍流程:端點會回傳什麼、怎麼分頁抓取數千個商品、如何在不被封鎖的前提下處理速率限制,以及怎麼用 pandas 把 Shopify 的巢狀 JSON 攤平成乾淨的 CSV 或 Excel 檔。我也會介紹其他文章比較少提到的端點(/collections.json、/meta.json),最後再提供一個免寫程式的替代方案,給想直接跳過 Python 的人。
Shopify 的 /products.json 端點是什麼?為什麼它讓抓取變得這麼簡單?
每個 Shopify 商店都有一個公開端點 {store-url}/products.json,會回傳結構化的商品資料。沒有 API 金鑰、沒有 OAuth、也不用任何驗證。你只要把 /products.json 接到商店網址後面,就能拿到整個商品目錄的 JSON 陣列。
你現在就可以自己試試看:在瀏覽器打開 或 。你會看到乾淨、結構清楚的 JSON,裡面包含商品標題、價格、變體、圖片、標籤等資訊。
跟另一種做法比起來差異就很明顯:解析 Shopify 的 HTML 主題頁面,通常結構一層包一層、不同商店的格式也不一樣,而且商家只要一更新主題,整個結構就可能變掉。你要處理的會是這種東西:
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=(分頁)——後面的範例會大量用到。
要注意的是:這是 公開的商店前台端點,不是 。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?常見商業應用場景
為什麼值得做?因為投資報酬率很高。現在都會用自動化價格抓取來做競爭情報分析,遠高於 2020 年的 34%。研究也顯示,。這些資料真的很有價值。
以下是我最常看到的應用情境:
| 應用場景 | 受益對象 | 你能得到什麼 |
|---|---|---|
| 競品價格監控 | 電商營運團隊 | 追蹤競品目錄中的價格變動、折扣與比價價格 |
| 商品研究與採購 | 採購/商品企劃 | 比較商品特色、變體、材質與庫存可得性 |
| 名單開發 | 業務團隊 | 從商店目錄擷取供應商名稱、品牌資料與聯絡資訊 |
| 市場與品類分析 | 行銷團隊 | 了解商品組合、標籤、集合分類結構與定位 |
| 庫存與供應狀態追蹤 | 供應鏈團隊 | 監控變體層級的庫存狀態(available: true/false) |
| 新品偵測 | 產品團隊 | 追蹤 created_at 時間戳,找出競品新品上架時間 |
Python 是做這件事的自然選擇。都把 Python 當作主要語言,而 requests 負責 HTTP、pandas 處理資料、httpx 可以做非同步,讓你能在 80 行以內的程式碼中,從「我有一個網址」一路做到「我有一份試算表」。
完整的 products.json 欄位參考:每個欄位都幫你拆解好
很多教學只會展示 title、id 和 handle,然後就草草帶過。但 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_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 | 圖片尺寸 |
公開端點沒有的欄位
有一個很重要的坑:公開的 /products.json 回應中沒有 inventory_quantity。 這個欄位在 2017 年 12 月就從公開 JSON 端點移除了,原因是安全性考量。你能拿到的唯一庫存指標,是每個變體上的布林欄位 available(true 或 false)。如果你要真正的庫存數量,就必須使用有驗證的 Admin API,並且具備商店擁有者權限。
在寫程式之前,先看過這張表,決定哪些欄位跟你的需求相關。如果你是做價格監控,就需要 variants[].price、variants[].compare_at_price 和 variants[].available。如果你是做名單開發,就聚焦在 vendor、product_type 和 tags。先過濾再輸出,CSV 會乾淨很多。
不只 products.json:Collections、Meta 與其他 Shopify 端點
很少有競品教學會提到這些端點,但如果你在做比較嚴謹的競爭情報分析,它們非常重要。
/collections.json — 商店所有分類
會回傳商店內所有集合(分類),包含標題、handle、描述和商品數量。我在 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。有了這個數字,你就能先算出需要幾頁分頁: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,也就是你必須擁有商店存取權。公開端點只提供商品目錄資料。

用 Python 抓 Shopify:一步一步設定教學
- 難度: 初學者
- 所需時間: 約 15 分鐘(設定 + 第一次抓取)
- 你需要準備: Python 3.11 以上、
pip、終端機,以及一個要抓取的 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
執行時如果沒有 import 錯誤,就代表安裝正常。如果 pandas 出現版本錯誤,請升級到 Python 3.12。
步驟 2:從 /products.json 取得商品資料
下面是一個基本函式,輸入商店網址後,會向端點發送請求並回傳解析後的 JSON:
1def fetch_products_page(store_url, page=1, limit=250):
2 """從 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", [])
幾個重點:
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:處理分頁,把所有商品都抓下來
單次請求最多只能拿到 250 個商品。很多商店都超過這個數量(Allbirds 就有 1,420+ 個)。你需要持續迴圈翻頁,直到拿到空回應。
1def scrape_all_products(store_url, delay=1.0):
2 """抓取 Shopify 商店的所有商品,並處理分頁。"""
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 # 禮貌一點:每次請求之間稍微等一下
15 time.sleep(delay + random.uniform(0, 0.5))
16 return all_products
當 products 回傳空陣列時,就代表已經抓到最後一頁。
time.sleep() 再加上隨機抖動,可以把請求頻率維持在 Shopify 大致可接受的非正式速率限制內(約每秒 2 次)。
小技巧:如果你先抓 /meta.json,就能知道總商品數,直接算出需要幾頁:pages = ceil(product_count / 250)。這樣就不會在最後多送一次空請求。
步驟 4:解析並挑選你需要的欄位
現在你已經拿到一個由字典組成的 Python list,接著只要擷取你關心的欄位即可。以下範例示範如何抓出最常見的價格監控欄位:
1def extract_product_data(products):
2 """從商品中擷取關鍵欄位,並將變體展平。"""
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 種顏色),每個變體都有自己的價格與可售狀態。
用 pandas 將抓取到的 Shopify 資料匯出成 CSV 與 Excel
其他 Shopify 抓取教學通常只會把原始 JSON 存成檔案就結束了。對開發者來說還行,對需要在週五前交出試算表的電商分析師來說,根本不夠。
問題在於:Shopify 的 JSON 是巢狀結構。一個商品可能包含十幾個變體,而每個變體都有自己的價格、SKU 和可售性。要把它攤平成列與欄,就需要借助 pandas。
把巢狀 JSON 攤平成乾淨表格
根據你的需求,可以有兩種做法:
方案 A:一個變體一列(最適合價格監控與庫存追蹤)
1# 使用步驟 4 的 extract_product_data 函式
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 個變體的商店,最後大約會產生 2,000 列的 DataFrame。
方案 B:一個商品一列的摘要表(最適合做目錄總覽)
1def summarize_products(products):
2 """每個商品一列,顯示各變體的最低/最高價格。"""
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(使用 utf-8-sig,讓 Excel 能正確處理特殊字元)
2df.to_csv("shopify_products.csv", index=False, encoding="utf-8-sig")
3# 匯出 Excel(需要 openpyxl)
4df.to_excel("shopify_products.xlsx", index=False, engine="openpyxl")
5print("已匯出為 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 萬+ 商品 |
進階方案(多數使用者都適合):
1import requests
2from requests.adapters import HTTPAdapter
3from urllib3.util.retry import Retry
4def create_session():
5 """建立一個具備自動重試機制的 requests session。"""
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 時自動做指數退避。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(小型目錄)測試過。
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 """建立具備速率限制重試邏輯的 session。"""
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 """透過 /products.json 抓取 Shopify 商店的所有商品。"""
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 """把巢狀商品 JSON 攤平成每個變體一列。"""
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" # 改成你的目標商店
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 秒,最後會產生一份約 5,000+ 列的 CSV(每個變體一列)。終端機輸出大概會像這樣:
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?用 Thunderbit 2 步驟抓 Shopify(免寫程式替代方案)
不是每個人都想安裝 Python、處理 import 錯誤,或維護抓取腳本。對於明天早上就要競品價格資料的業務來說,Python 可能太重了。
這也是我們打造 的原因——一款以 Chrome 擴充功能形式運作的 AI 網頁爬蟲。免寫程式、免 API 金鑰,也不用設定環境。
Thunderbit 如何抓 Shopify 商店
Thunderbit 內建專為 Shopify 商品頁設計的 Shopify 爬蟲範本。你只要安裝 ,打開 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。如果你想更深入了解 ,我們也另外寫了一篇專文。

抓 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
- 免寫程式替代方案:對於偏好速度勝過程式彈性的使用者,推薦
如果你只是要一次性或定期抓 Shopify 資料,又不想寫程式,可以試試 ——內建的 Shopify 爬蟲範本可處理從分頁到匯出的所有流程。如果你要為多個商店建立客製化資料管線,或要大規模抓取,這篇文章中的 Python 腳本會給你完整控制權。
也歡迎到我們的 看影片教學,或延伸閱讀我們關於 與 的相關指南。
常見問題
可以用 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 嗎?
當然可以。像 這類工具,就能透過 Chrome 擴充功能免寫程式抓取 Shopify 商店。它會自動處理分頁,並直接匯出到 CSV、Excel、Google Sheets、Airtable 或 Notion。若你是偏好其他語言的開發者,同樣的 /products.json 端點也能搭配 JavaScript、Ruby、Go——任何能送出 HTTP 請求並解析 JSON 的語言都可以。
延伸閱讀
