ปลายทาง /products.json ของ Shopify นี่แหละถือเป็นหนึ่งใน “ความลับที่ไม่ค่อยลับ” ที่สุดในวงการข้อมูลอีคอมเมิร์ซ แค่เติมท้าย URL ของร้าน Shopify เข้าไป ก็จะได้ JSON ที่มีโครงสร้างพร้อมใช้งานกลับมาเลย—ไม่ต้องมี API key, ไม่ต้องยืนยันตัวตน, ไม่ต้องมานั่งแกะ HTML ที่ซ้อนกันเป็นชั้น ๆ ให้ปวดหัว
ผมทำงานอยู่กับทีม เลยคลุกกับเรื่องการดึงข้อมูลจากเว็บพอสมควร และการ scrape Shopify ก็เป็นหัวข้อที่ถูกถามเข้ามาตลอด—ทั้งจากทีมขายที่ต้องตามดูราคาคู่แข่ง คนทำอีคอมเมิร์ซที่ต้องเทียบแค็ตตาล็อกสินค้า ไปจนถึงทีมจัดซื้อที่กำลังมองหาซัพพลายเออร์รายใหม่ ๆ ด้วย บน Shopify และส่วนแบ่งราว ปริมาณข้อมูลสินค้าที่ดึงออกมาได้จึงมหาศาลมาก
คู่มือนี้จะพาไล่ตั้งแต่ต้นจนจบ: endpoint นี้คืนค่าอะไรบ้าง, จะไล่ pagination ยังไงให้ดึงสินค้าได้เป็นพันรายการ, จะรับมือ rate limit โดยไม่โดนบล็อกยังไง, และจะทำให้ JSON ที่ซ้อนกันของ Shopify กลายเป็น CSV หรือไฟล์ Excel ที่อ่านง่ายด้วย pandas ได้อย่างไร ผมยังจะพูดถึง endpoint อื่นที่คนไม่ค่อยพูดถึง (/collections.json, /meta.json) และแถมทางเลือกแบบ no-code สำหรับคนที่ไม่อยากแตะ Python เลยด้วย
/products.json ของ Shopify คืออะไร และทำไมถึงดึงข้อมูลได้ง่าย
ร้าน Shopify ทุกแห่งจะมี endpoint สาธารณะที่ {store-url}/products.json ซึ่งคืนข้อมูลสินค้าที่เป็นโครงสร้างชัดเจนมาให้ ไม่ต้องใช้ API key ไม่ต้องใช้ OAuth ไม่ต้องล็อกอินใด ๆ แค่เติม /products.json ต่อท้าย URL ของร้าน ก็จะได้ JSON array ของสินค้าทั้งหมดในแค็ตตาล็อกกลับมา
ลองเปิดดูได้เลยตอนนี้: เข้าไปที่ หรือ ในเบราว์เซอร์ คุณจะเห็น JSON ที่สะอาดและเป็นระเบียบ มีทั้งชื่อสินค้า ราคา ตัวเลือกสินค้า รูปภาพ แท็ก และข้อมูลอื่น ๆ ครบ
ถ้าเทียบกับวิธีอื่น เช่น การไล่ parse 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 ชนะทั้งเรื่องความสม่ำเสมอ ความเสถียร และความง่ายในการ parse นอกจากนี้ endpoint นี้ยังรองรับ query parameter สำคัญ 2 ตัวคือ ?limit= (สูงสุด 250 สินค้าต่อหน้า ค่าเริ่มต้นคือ 30) และ ?page= สำหรับ pagination ซึ่งเราจะใช้กันเยอะมากในโค้ดด้านล่าง
สิ่งที่ต้องแยกให้ออก: นี่คือ public storefront endpoint ไม่ใช่ โดย Admin API ต้องใช้ access token ของเจ้าของร้าน และให้ข้อมูลเช่นออเดอร์ ระดับสต็อก และข้อมูลลูกค้า ส่วน /products.json แบบสาธารณะจะให้เฉพาะข้อมูลสินค้าที่อ่านได้อย่างเดียว ใคร ๆ ก็เข้าถึงได้ เดี๋ยวผมจะอธิบายความต่างนี้ให้ชัดขึ้นอีกครั้งด้านล่าง เพราะมีคนสับสนเรื่องนี้บ่อยมาก
ข้อควรระวัง: ไม่ใช่ทุกร้าน Shopify จะเปิด endpoint นี้ไว้ จากที่ผมทดสอบ ประมาณ 71% ของร้านจะคืน JSON ที่ใช้งานได้ (เช่น allbirds.com, gymshark.com, colourpop.com, kyliecosmetics.com ใช้ได้หมด) แต่บางร้านที่ตั้งค่าเองอาจได้ 404 (เช่น hiutdenim.co.uk, bombas.com) วิธีเช็กเร็ว ๆ คือเข้า {store-url}/products.json ในเบราว์เซอร์แล้วดูผลลัพธ์
ทำไมต้อง scrape Shopify ด้วย Python? ตัวอย่างการใช้งานทางธุรกิจ
แล้วทำไปเพื่ออะไร? คำตอบคือ ROI นั่นเอง ใช้ automated price scraping เพื่อทำ competitive intelligence แล้ว จากเดิมมีแค่ 34% ในปี 2020 และงานวิจัยยังพบว่า ข้อมูลพวกนี้มีมูลค่าจริง ๆ
กรณีใช้งานที่พบบ่อยที่ผมเห็นมีดังนี้:
This paragraph contains content that cannot be parsed and has been skipped.
Python เหมาะกับงานนี้ที่สุด ใช้ Python เป็นภาษาหลักอยู่แล้ว และ ecosystem อย่าง requests สำหรับ HTTP, pandas สำหรับจัดการข้อมูล, httpx สำหรับ async ทำให้เปลี่ยนจาก "มีแค่ URL" ไปเป็น "มีสเปรดชีตพร้อมใช้" ได้ในโค้ดไม่ถึง 80 บรรทัด
อ้างอิงฟิลด์ products.json แบบครบถ้วน: มีอะไรให้ดึงบ้าง
บทความสอน scrape ส่วนใหญ่จะโชว์แค่ title, id, กับ handle แล้วก็จบ แต่ JSON response ของ Shopify จริง ๆ มีฟิลด์มากกว่า 40 รายการ ครอบคลุมทั้ง product, variant, image และ options การรู้ว่ามีอะไรให้ใช้บ้างก่อนเริ่มเขียนโค้ด จะช่วยให้ไม่ต้องกลับมาดึงข้อมูลใหม่ทีหลัง
อ้างอิงนี้ผมรวบรวมจาก response จริงของ /products.json ที่ดึงเมื่อวันที่ 16 เมษายน 2026 โครงสร้างจะเหมือนกันในทุก store ที่เปิด endpoint นี้ไว้
ฟิลด์ระดับสินค้า
| ฟิลด์ | ชนิดข้อมูล | ตัวอย่างค่า | การใช้งานทางธุรกิจ |
|---|---|---|---|
id | Integer | 123456789 | รหัสสินค้าที่ไม่ซ้ำ ใช้ deduplicate |
title | String | "Classic Blue Jeans" | ชื่อสินค้าสำหรับแค็ตตาล็อกและการเปรียบเทียบ |
handle | String | "classic-blue-jeans" | slug ของ URL—ใช้สร้างลิงก์สินค้าเป็น {store}/products/{handle} |
body_html | String (HTML) หรือ null | Our best-selling... | คำอธิบายสินค้า ใช้วิเคราะห์คอนเทนต์และ SEO |
vendor | String | "Hiut Denim" | ชื่อแบรนด์/ซัพพลายเออร์ ใช้ทำ 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"] | วิเคราะห์คีย์เวิร์ด/แท็กเพื่อ SEO การจัดหมวดหมู่ และเทรนด์ |
variants | Array of Objects | (ดูฟิลด์ variant ด้านล่าง) | ราคา SKU และความพร้อมขายของแต่ละ variant |
images | Array of Objects | (ดูฟิลด์ image ด้านล่าง) | URL รูปสินค้า ใช้ทำแค็ตตาล็อกและวิเคราะห์เชิงภาพ |
options | Array of Objects | [{"name": "Size", "values": ["S","M","L"]}] | ทำความเข้าใจโครงสร้างตัวเลือกสินค้า (ไซซ์ สี วัสดุ) |
ฟิลด์ระดับ Variant (ซ้อนอยู่ใต้สินค้าแต่ละชิ้น)
| ฟิลด์ | ชนิดข้อมูล | ตัวอย่าง | การใช้งาน |
|---|---|---|---|
id | Integer | 987654321 | รหัส variant ที่ไม่ซ้ำ |
title | String | "32 / Blue" | ชื่อที่แสดงของ variant |
sku | String | "HD-BLU-32" | ใช้จับคู่ SKU กับระบบสต็อก |
price | String | "185.00" | ใช้ติดตามราคา (หมายเหตุ: เป็น string ต้องแปลงเป็น float ก่อนคำนวณ) |
compare_at_price | String หรือ null | "200.00" | ราคาตั้งต้น—สำคัญมากสำหรับการติดตามส่วนลด |
available | Boolean | true | สถานะพร้อมขาย (ตัวบอกสต็อกที่เปิดให้ดูได้) |
weight | Float | 1.2 | ใช้วิเคราะห์การขนส่ง/โลจิสติกส์ |
option1, option2, option3 | String | "32", "Blue", null | ค่าของตัวเลือกแต่ละตัว |
created_at, updated_at | ISO DateTime | — | ใช้ติดตามการเปลี่ยนแปลงระดับ variant |
ฟิลด์ระดับ Image
| ฟิลด์ | ชนิดข้อมูล | ตัวอย่าง | การใช้งาน |
|---|---|---|---|
id | Integer | 111222333 | รหัสรูปภาพที่ไม่ซ้ำ |
src | String (URL) | "https://cdn.shopify.com/..." | ลิงก์ดาวน์โหลดรูปโดยตรง |
alt | String หรือ null | "Front view of jeans" | alt text ของรูป ใช้วิเคราะห์ accessibility |
position | Integer | 1 | ลำดับของรูป |
width, height | Integer | 2048, 2048 | ขนาดของรูปภาพ |
อะไรที่ไม่มีใน Public Endpoint
มีจุดที่ต้องระวังมากคือ inventory_quantity ไม่มีให้ใน response ของ /products.json แบบสาธารณะ ฟิลด์นี้ถูกเอาออกจาก JSON ที่เปิดให้สาธารณะตั้งแต่เดือนธันวาคม 2017 ด้วยเหตุผลด้านความปลอดภัย สิ่งที่ดูได้จาก public endpoint คือแค่ค่า boolean available ของแต่ละ variant (true หรือ false) ถ้าต้องการตัวเลขสต็อกจริง ๆ ต้องใช้ Admin API ที่ยืนยันตัวตนแล้วเท่านั้น
ก่อนเริ่มเขียนโค้ด ลองดูตารางนี้แล้วตัดสินใจว่า field ไหนสำคัญกับงานของคุณ ถ้าเป็นงานติดตามราคา คุณต้องใช้ variants[].price, variants[].compare_at_price, และ variants[].available ถ้าเป็นงานหาลีด ให้เน้น vendor, product_type, และ tags คัดให้ตรงตั้งแต่ต้น จะช่วยให้ CSV สะอาดกว่าเยอะ
นอกจาก products.json ยังมี Collections, Meta และ endpoint อื่นของ Shopify
บทความสอน scrape ทั่วไปแทบไม่พูดถึง endpoint เหล่านี้ แต่ถ้าทำ competitive intelligence แบบจริงจัง มันสำคัญมาก
/collections.json — หมวดหมู่สินค้าทั้งหมดของร้าน
คืนข้อมูล collection (หมวดหมู่) ทุกอันในร้าน พร้อมชื่อ, 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}
ถ้าอยากรู้ว่า competitor จัดโครงสร้างแค็ตตาล็อกยังไง endpoint นี้แหละคือคำตอบ
/collections/{handle}/products.json — สินค้าตามหมวดหมู่
คืนสินค้าที่กรองตาม collection เฉพาะ หมายเหตุคือโครงสร้าง JSON เหมือน /products.json แต่จำกัดอยู่แค่หนึ่งหมวดหมู่เท่านั้น สำคัญมากสำหรับการ scrape ระดับหมวดหมู่—เช่นคุณอยากติดตามเฉพาะคอลเลกชัน “Sale” หรือ “New Arrivals” ของคู่แข่ง
/meta.json — เมตาข้อมูลระดับร้าน
คืนชื่อร้าน, คำอธิบาย, สกุลเงิน, ประเทศ และส่วนที่มีประโยชน์ที่สุดคือ published_products_count ตัวเลขนี้ช่วยให้คุณคำนวณได้ล่วงหน้าว่าต้องใช้ pagination กี่หน้า: ceil(published_products_count / 250) ไม่ต้องเดาแบบสุ่มแล้วไล่เพิ่ม page ไปเรื่อย ๆ จนเจอ response ว่าง
ควรใช้ endpoint ไหน
| สิ่งที่ต้องการ | Endpoint | ต้องยืนยันตัวตนไหม |
|---|---|---|
| สินค้าทั้งหมด (สาธารณะ) | /products.json | ไม่ต้อง |
| สินค้าในหมวดหมู่เฉพาะ | /collections/{handle}/products.json | ไม่ต้อง |
| เมตาข้อมูลร้าน + จำนวนสินค้า | /meta.json | ไม่ต้อง |
| คอลเลกชัน (หมวดหมู่) ทั้งหมด | /collections.json | ไม่ต้อง |
| ข้อมูลออเดอร์/ยอดขาย (เฉพาะร้านตัวเอง) | Admin API /orders.json | ต้องใช้ (API key) |
| ปริมาณสต็อก (เฉพาะร้านตัวเอง) | Admin API /inventory_levels.json | ต้องใช้ |
คำถามที่เจอบ่อยในฟอรั่ม—"จะ scrape ดูได้ไหมว่าคู่แข่งขายไปกี่ชิ้น"—คำตอบสั้น ๆ คือ ไม่ได้ ถ้าใช้แค่ public endpoint ข้อมูลยอดขายและจำนวนสต็อกต้องใช้ Admin API ที่ยืนยันตัวตนแล้ว ซึ่งหมายความว่าคุณต้องมีสิทธิ์ของเจ้าของร้าน Public endpoint ให้ได้แค่ข้อมูลแค็ตตาล็อกสินค้าเท่านั้น

วิธี scrape Shopify ด้วย Python แบบทีละขั้น
- ระดับความยาก: มือใหม่
- เวลาที่ใช้: ประมาณ 15 นาที (ตั้งค่า + scrape ครั้งแรก)
- สิ่งที่ต้องมี: Python 3.11+,
pip, terminal และ URL ของร้าน Shopify ที่ต้องการ scrape
ขั้นตอนที่ 1: ติดตั้ง Python และไลบรารีที่จำเป็น
ตรวจให้แน่ใจว่าคุณติดตั้ง Python 3.11 หรือใหม่กว่าแล้ว (pandas 3.0.x ต้องการเวอร์ชันนี้) จากนั้นติดตั้งไลบรารีสองตัวที่ต้องใช้:
1pip install requests pandas
ถ้าจะ export เป็น Excel ด้วย ก็ให้ติดตั้งด้วย:
1pip install openpyxl
ที่หัวสคริปต์ ให้เพิ่ม import เหล่านี้:
1import requests
2import pandas as pd
3import time
4import random
5import json
ถ้ารันสคริปต์แล้วควรจะไม่เจอ import error ถ้า pandas ฟ้องเรื่องเวอร์ชัน ให้ขยับไปใช้ Python 3.12
ขั้นตอนที่ 2: ดึงข้อมูลสินค้าจาก /products.json
นี่คือฟังก์ชันพื้นฐานที่รับ URL ร้านค้า, เรียก endpoint และคืนค่า JSON ที่ parse แล้ว:
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 ดังนั้นการตั้งค่านี้ช่วยลดจำนวน request ลงได้มากถึง 8 เท่า- header
User-Agent: ควรตั้งให้ดูสมจริงเสมอ request ที่ไม่มี 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 รายการ) คุณจึงต้องวนทีละหน้าไปเรื่อย ๆ จนกว่าจะได้ response ว่างกลับมา
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 # อย่าเร่งเกินไป: เว้นช่วงระหว่าง request
15 time.sleep(delay + random.uniform(0, 0.5))
16 return all_products
เมื่อ products กลับมาว่าง แปลว่าไปถึงหน้าสุดท้ายแล้ว
การใช้ time.sleep() พร้อมสุ่ม jitter เล็กน้อยช่วยให้คุณอยู่ต่ำกว่าขีดจำกัด rate limit แบบไม่เป็นทางการของ Shopify (ประมาณ 2 request/วินาที)
ทริกเพิ่มประสิทธิภาพ: ถ้าคุณดึง /meta.json มาก่อน คุณจะรู้จำนวนสินค้าทั้งหมดอยู่แล้ว และสามารถคำนวณจำนวนหน้าที่ต้องใช้ได้เป๊ะ ๆ ด้วย pages = ceil(product_count / 250) แบบนี้จะไม่ต้องยิง request ว่างเกินมา 1 ครั้งท้ายสุด
ขั้นตอนที่ 4: แยกฟิลด์ที่ต้องการออกมาใช้งาน
เมื่อคุณได้สินค้าทั้งหมดเป็น Python list ของ dictionary แล้ว ก็แค่ดึงเฉพาะฟิลด์ที่ต้องใช้ ตัวอย่างนี้ดึงฟิลด์ยอดนิยมสำหรับงานติดตามราคา:
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
โค้ดนี้จะสร้าง 1 แถวต่อ 1 variant ซึ่งเป็นรูปแบบที่มีประโยชน์มากที่สุดสำหรับการเปรียบเทียบราคา เพราะสินค้าชิ้นหนึ่ง เช่น "Classic Blue Jeans" อาจมีถึง 12 variant (6 ไซซ์ × 2 สี) และแต่ละ variant ก็มีราคาและสถานะพร้อมขายต่างกัน
ส่งออก Shopify ที่ scrape ได้เป็น CSV และ Excel ด้วย pandas
บทความสอน scrape Shopify ส่วนใหญ่จบที่การ dump raw JSON ลงไฟล์แล้วถือว่าเสร็จ แต่แบบนั้นเหมาะกับนักพัฒนา ทว่าไม่ค่อยมีประโยชน์กับนักวิเคราะห์อีคอมเมิร์ซที่ต้องการสเปรดชีตไปใช้ภายในวันศุกร์
ปัญหาคือ JSON ของ Shopify ซ้อนกันหลายชั้น สินค้าหนึ่งชิ้นมี variant ได้เป็นสิบ ๆ ตัว และแต่ละตัวก็มีราคา SKU และ availability ของตัวเอง การแปลงให้เป็นแถวและคอลัมน์จึงต้องใช้ pandas ช่วย
แปลง JSON ซ้อนเป็นตารางที่อ่านง่าย
มี 2 วิธีหลัก ขึ้นอยู่กับวัตถุประสงค์:
ตัวเลือก A: 1 แถวต่อ 1 variant (เหมาะที่สุดสำหรับงานติดตามราคาและสต็อก)
1# ใช้ฟังก์ชัน extract_product_data จากขั้นตอนที่ 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())
วิธีนี้จะได้ตารางแบบ flat ซึ่งแต่ละแถวคือคู่ product-variant ที่ไม่ซ้ำกัน ร้านที่มี 500 สินค้า และเฉลี่ยสินค้า 1 ชิ้นมี 4 variant ก็จะได้ DataFrame ประมาณ 2,000 แถว
ตัวเลือก B: 1 แถวต่อ 1 สรุปสินค้า (เหมาะกับภาพรวมแค็ตตาล็อก)
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# Export เป็น CSV (ใช้ utf-8-sig เพื่อให้ Excel อ่านอักขระพิเศษได้)
2df.to_csv("shopify_products.csv", index=False, encoding="utf-8-sig")
3# Export เป็น Excel (ต้องใช้ 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 แล้วอัปโหลดเข้า Google Drive จะเร็วและง่ายกว่า
สแครปแบบใช้งานจริง: rate limit, retry และการหลบการบล็อก
สคริปต์พื้นฐานจะใช้งานได้ดีกับร้านเล็ก ๆ แต่ถ้าจะสแครปร้านที่มีสินค้ามากกว่า 5,000 รายการ หรือไล่หลายร้านต่อเนื่อง ปัญหาจะเริ่มโผล่
เข้าใจ rate limit และพฤติกรรมการบล็อกของ Shopify
public JSON endpoints ของ Shopify ไม่มีการระบุ rate limit แบบเป็นทางการ (ต่างจาก Admin API ที่มี leaky bucket model) แต่จากการทดสอบจริงพบว่า:
- อัตราที่ปลอดภัย: ประมาณ 2 request ต่อวินาทีต่อร้าน
- เพดานแบบนุ่ม ๆ: ประมาณ 40 request ต่อนาที ก่อนเริ่มโดน throttle
- HTTP 429: "Too Many Requests" คือ response มาตรฐานเมื่อโดนจำกัดอัตรา
- HTTP 430: โค้ดเฉพาะของ Shopify ที่บอกว่าถูกบล็อกระดับ security ไม่ใช่แค่ rate limit
- HTTP 403 หรือ redirect ไป CAPTCHA: บางร้านมี Cloudflare หรือระบบป้องกันเพิ่ม
request ที่มาจาก cloud infrastructure ร่วมกัน เช่น AWS Lambda หรือ Google Cloud Run มีโอกาสโดนบล็อกมากเป็นพิเศษ เพราะ IP เหล่านั้นมักถูกใช้แบบผิดปกติค่อนข้างสูง
เทคนิคให้ scrape Shopify ได้เสถียร
นี่คือพัฒนาการจาก "รันได้บนเครื่องฉัน" ไปสู่ "พร้อมใช้งานจริง":
| ระดับ | เทคนิค | ความน่าเชื่อถือ |
|---|---|---|
| ขั้นพื้นฐาน | 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
4> This paragraph contains content that cannot be parsed and has been skipped.
5การตั้งค่า `Retry` จะจัดการ 429 ให้อัตโนมัติด้วย exponential backoff โดย `backoff_factor=1` หมายถึงช่วงเวลาหน่วงจะเป็น 0.5s → 1s → 2s → 4s → 8s ระหว่างการ retry นอกจากนี้การใช้ `requests.Session()` ซ้ำยังช่วยให้มี connection pooling ลด overhead เวลา request ไปโดเมนเดิมหลายครั้ง
6**การสลับ User-Agent**: ถ้าคุณ scrape หลายร้าน ให้สลับระหว่าง browser User-Agent ที่สมจริง 3–5 แบบ ไม่ใช่เพื่อหลอกใคร แต่เพื่อไม่ให้ดูเหมือนบอทที่ส่ง header เดิมทุก request
7<iframe width="560" height="315" src="https://www.youtube.com/embed/p3Z-qtUp4p8" title="Web Scraping Project: Save Shopify Products to Database" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen></iframe>
8## สคริปต์ Python ฉบับสมบูรณ์สำหรับ scrape Shopify พร้อม export CSV
9นี่คือสคริปต์ฉบับเต็มแบบคัดลอกไปใช้ได้เลย ที่รวมทุกอย่างข้างบนเข้าไว้ด้วยกัน โค้ดจริงประมาณ 75 บรรทัด (ยังไม่รวมคอมเมนต์) และผมทดสอบกับ Allbirds (1,420 สินค้า), ColourPop (2,000+ สินค้า) และ Zoologist Perfumes (แค็ตตาล็อกเล็ก)
10```python
11import requests
12import pandas as pd
13import time
14import random
15from requests.adapters import HTTPAdapter
16from urllib3.util.retry import Retry
17> This paragraph contains content that cannot be parsed and has been skipped.
18def scrape_shopify(store_url, delay=1.0):
19 """Scrape all products from a Shopify store via /products.json."""
20 session = create_session()
21 all_products = []
22 page = 1
23 base_url = f"{store_url.rstrip('/')}/products.json"
24> This paragraph contains content that cannot be parsed and has been skipped.
25 if not products:
26 break
27 all_products.extend(products)
28 print(f"{len(products)} products (total: {len(all_products)})")
29 page += 1
30 time.sleep(delay + random.uniform(0, 0.5))
31 return all_products
32> This paragraph contains content that cannot be parsed and has been skipped.
33if __name__ == "__main__":
34 STORE_URL = "https://allbirds.com" # เปลี่ยนเป็นร้านเป้าหมายของคุณ
35 OUTPUT_CSV = "shopify_products.csv"
36 OUTPUT_EXCEL = "shopify_products.xlsx"
37 print(f"Scraping {STORE_URL}...")
38 products = scrape_shopify(STORE_URL)
39 print(f"\nTotal products scraped: {len(products)}")
40 print("Flattening to variant-level rows...")
41 rows = flatten_to_variants(products)
42 df = pd.DataFrame(rows)
43 print(f"DataFrame: {df.shape[0]} rows x {df.shape[1]} columns")
44 df.to_csv(OUTPUT_CSV, index=False, encoding="utf-8-sig")
45 df.to_excel(OUTPUT_EXCEL, index=False, engine="openpyxl")
46 print(f"\nExported to {OUTPUT_CSV} and {OUTPUT_EXCEL}")
รันด้วย python scrape_shopify.py สำหรับ Allbirds ใช้เวลาประมาณ 45 วินาที และจะได้ CSV ที่มีข้อมูลประมาณ 5,000+ แถว (หนึ่งแถวต่อหนึ่ง variant) เอาต์พุตในเทอร์มินัลจะออกมาประมาณนี้:
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 error หรือคอยดูแลสคริปต์ scrape เอง สำหรับเซลส์ที่ต้องรู้ราคาคู่แข่งพรุ่งนี้เช้า Python อาจเกินจำเป็น
นั่นจึงเป็นเหตุผลที่เราสร้าง ขึ้นมา—AI web scraper ที่ทำงานเป็น Chrome extension ไม่ต้องเขียนโค้ด ไม่ต้องใช้ API key ไม่ต้องตั้ง environment
Thunderbit scrape ร้าน Shopify อย่างไร
Thunderbit มี Shopify Scraper template เฉพาะที่ตั้งค่ามาให้พร้อมสำหรับหน้าสินค้า Shopify อยู่แล้ว แค่ติดตั้ง เข้าไปที่ร้าน Shopify แล้วกด "Scrape" ระบบจะดึงชื่อสินค้า คำอธิบาย ราคา รายละเอียด variant รูปภาพ และข้อมูล vendor ให้โดยอัตโนมัติ
สำหรับร้านที่ template ไม่ตรงพอดี (เช่นธีมปรับแต่งเองหรือเลย์เอาต์แปลก ๆ) ฟีเจอร์ AI Suggest Fields ของ Thunderbit จะอ่านหน้าเว็บแล้วสร้างชื่อคอลัมน์ให้อัตโนมัติ คุณสามารถปรับแต่งต่อได้—เปลี่ยนชื่อคอลัมน์ เพิ่มฟิลด์ หรือเขียนคำสั่งเช่น "ดึงเฉพาะสินค้าที่มี compare_at_price เท่านั้น"
ฟีเจอร์บางอย่างของ Thunderbit เทียบตรงกับสิ่งที่สคริปต์ Python ทำได้:
- Subpage scraping: เข้าไปยังหน้ารายละเอียดสินค้าทีละหน้าโดยอัตโนมัติ แล้วเติมข้อมูลคำอธิบายเต็ม รีวิว หรือรายละเอียด variant ลงในตาราง—สิ่งเดียวกับที่สคริปต์ Python ทำผ่านการไล่หน้า แต่ไม่ต้องเขียนโค้ดเลย
- Automatic pagination: จัดการ pagination แบบ click-through และ infinite scroll ให้โดยไม่ต้องตั้งค่า
- Scheduled scraping: ตั้งงานให้รันซ้ำเป็นรอบ ๆ (เช่น “ทุกวันจันทร์ 9 โมงเช้า”) สำหรับเฝ้าดูราคาอย่างต่อเนื่อง—ไม่ต้องมี cron job หรือเซิร์ฟเวอร์
- ส่งออกฟรี ไป CSV, Excel, Google Sheets, Airtable หรือ Notion ได้ทุกแพลน
เทียบ Python Script กับ Thunderbit แบบตรงไปตรงมา
| ปัจจัย | Python Script | Thunderbit (No-code) |
|---|---|---|
| เวลาเริ่มต้น | 15–60 นาที (ตั้งค่าสภาพแวดล้อม + โค้ด) | ประมาณ 2 นาที (ติดตั้ง Chrome extension) |
| ต้องเขียนโค้ดไหม | ต้อง (Python) | ไม่ต้อง |
| ปรับแต่งได้แค่ไหน | ไม่จำกัด | AI suggest fields + custom prompts |
| การจัดการ pagination | ต้องเขียนเอง | อัตโนมัติ |
| รูปแบบ export | ต้องเขียนเอง (CSV/Excel) | CSV, Excel, Google Sheets, Airtable, Notion (ฟรี) |
| การรันตามเวลา | ต้องมี cron job + hosting | มี scheduler ในตัว |
| การรับมือ rate limit | ต้องเขียน retry/backoff เอง | จัดการให้อัตโนมัติ |
| เหมาะกับใคร | นักพัฒนา, data pipeline ขนาดใหญ่ | ผู้ใช้งานธุรกิจ, งานดึงข้อมูลเร็ว ๆ, เฝ้าติดตามซ้ำ ๆ |
ใช้ Python เมื่อคุณต้องการควบคุมทุกอย่างเอง หรือกำลังเชื่อมเข้ากับ data pipeline ขนาดใหญ่ ใช้ Thunderbit เมื่อคุณต้องการข้อมูลเร็ว ๆ และไม่อยากเสียเวลาดูแลโค้ด สำหรับมุมมองเชิงลึกเรื่อง เรามีคู่มือแยกไว้อีกบทความหนึ่ง

เคล็ดลับและแนวทางปฏิบัติที่ดีในการ scrape ร้าน Shopify
ไม่ว่าคุณจะใช้เครื่องมืออะไร ข้อแนะนำเหล่านี้ก็ยังใช้ได้เสมอ:
- ใช้
?limit=250เสมอ เพื่อลดจำนวน request ให้เหลือน้อยที่สุด ค่าเริ่มต้น 30 ต่อหน้าจะทำให้ต้องยิง request มากกว่าเดิมถึง 8 เท่าเพื่อข้อมูลเท่าเดิม - เคารพเซิร์ฟเวอร์ของร้าน: เว้นช่วง 1–2 วินาทีระหว่าง request การยิงถี่ ๆ ไม่ใช่แค่เสียมารยาท แต่ยังเพิ่มโอกาสโดนบล็อกด้วย
- เช็ก
robots.txtก่อน:robots.txtมาตรฐานของ Shopify จะไม่บล็อก/products.jsonแต่บางร้านเพิ่มกฎเอง จึงควรตรวจสอบก่อน scrape ขนาดใหญ่ - เก็บ raw JSON ไว้ก่อน แล้วค่อย process ถ้ากติกาการ parse เปลี่ยนทีหลัง คุณจะไม่ต้อง scrape ใหม่ทั้งหมด การ
json.dump(all_products, open("raw_data.json", "w"))ก่อน flatten ช่วยลดปวดหัวได้มาก - deduplicate ด้วย
product.id: บางครั้ง pagination ที่ขอบหน้าอาจคืนสินค้าซ้ำกันได้ การใช้df.drop_duplicates(subset=["product_id", "variant_id"])ช่วยจัดการได้ - แปลง
priceเป็น float ก่อนคำนวณ เพราะ Shopify ส่งราคากลับมาเป็น string (เช่น "185.00") ไม่ใช่ตัวเลข - เฝ้าดูการเปลี่ยนแปลงของ endpoint: แม้
/products.jsonจะเสถียรมาหลายปี แต่ Shopify ก็อาจจำกัดการเข้าถึงในอนาคตได้ ถ้า scraper ใช้ไม่ได้กะทันหัน ให้ลองเช็กร้านด้วยมือก่อน
ถ้าอยากเรียนรู้เรื่องการสร้าง scraper ที่ทนทานมากขึ้น ลองอ่านคู่มือ ของเรา
ข้อควรพิจารณาด้านกฎหมายและจริยธรรมเมื่อ scrape Shopify
เป็นหัวข้อสั้น ๆ แต่สำคัญมาก
endpoint /products.json ให้ข้อมูลสินค้าที่เปิดเผยต่อสาธารณะ—ข้อมูลเดียวกับที่ผู้เข้าชมร้านทั่วไปเห็นได้ Shopify Terms of Service มีถ้อยคำเกี่ยวกับการไม่ใช้ "automated means" เพื่อเข้าถึง "the Services" แต่คำนี้หมายถึงตัวแพลตฟอร์มเอง (เช่นแดชบอร์ดผู้ดูแล ระบบเช็กเอาต์) ไม่ใช่ข้อมูลหน้าร้านที่เปิดสาธารณะ ณ เดือนเมษายน 2026 ยังไม่มีคดีฟ้องร้องเกี่ยวกับการ scrape Shopify โดยตรง
บรรทัดฐานทางกฎหมายที่สนับสนุนการ scrape ข้อมูลสาธารณะมีอยู่แล้ว เช่น คดี hiQ v. LinkedIn ที่ระบุว่าการ scrape ข้อมูลที่เข้าถึงได้สาธารณะไม่ได้ละเมิด CFAA และคดี Meta v. Bright Data (2024) ก็วินิจฉัยว่าข้อจำกัดใน TOS ใช้ได้เมื่อผู้ใช้ล็อกอินอยู่เท่านั้น
แนวทางที่ควรทำ:
- scrape เฉพาะข้อมูลสินค้าที่เปิดเผยสาธารณะ
- อย่า scrape ข้อมูลส่วนบุคคลหรือลูกค้า
- เคารพ
robots.txtและ rate limit - ปฏิบัติตาม GDPR/CCPA หากต้องจัดการข้อมูลส่วนบุคคลใด ๆ (ข้อมูลแค็ตตาล็อกสินค้าไม่ใช่ข้อมูลส่วนบุคคล)
- ระบุตัวตนให้ชัดด้วย User-Agent string ที่เหมาะสม
- การ scrape ร้าน Shopify ของตัวเองผ่าน Admin API นั้นทำได้สบายอยู่แล้ว
ถ้าอยากอ่านให้ลึกขึ้น ลองดูโพสต์ ของเรา
สรุปและประเด็นสำคัญ
public /products.json ของ Shopify ทำให้การดึงข้อมูลอีคอมเมิร์ซง่ายมาก ๆ เวิร์กโฟลว์คือ: เติม /products.json → ดึงด้วย Python → ไล่ pagination ด้วย ?limit=250&page= → flatten ด้วย pandas → export เป็น CSV หรือ Excel
สิ่งที่คู่มือนี้ให้มากกว่าบทความอื่น:
- อ้างอิงฟิลด์แบบครบถ้วน: รู้เลยว่ามีข้อมูลอะไรให้ใช้บ้าง (มากกว่า 40 ฟิลด์ใน product, variant และ image) ก่อนเขียนโค้ดแม้แต่บรรทัดเดียว
- endpoint เพิ่มเติม:
/collections.jsonและ/meta.jsonช่วยให้ได้ข้อมูลระดับหมวดหมู่และ metadata ของร้าน ซึ่งบทความอื่นมักไม่พูดถึง - เทคนิคระดับ production: การใช้ session ซ้ำ, exponential backoff, User-Agent headers และ
?limit=250เพื่อรับมือ rate limit ของโลกจริง - การ export CSV/Excel ที่ถูกต้อง: flatten ข้อมูลระดับ variant ด้วย pandas ไม่ใช่ dump JSON ดิบ ๆ อย่างเดียว
- ทางเลือกแบบ no-code: สำหรับคนที่อยากได้ความเร็วมากกว่าความยืดหยุ่นของโค้ด
ถ้าคุณต้องการดึงข้อมูล Shopify แบบครั้งเดียวหรือแบบทำซ้ำโดยไม่เขียนโค้ด ลองใช้ ได้เลย—Shopify Scraper template จัดการทุกอย่างตั้งแต่ pagination ไปจนถึง export ให้ครบ สำหรับ data pipeline แบบกำหนดเอง หรือการ scrape หลายร้านในสเกลใหญ่ สคริปต์ Python ในคู่มือนี้ให้คุณควบคุมได้เต็มที่
แวะดู ของเราเพื่อดูวิดีโอสาธิต หรืออ่านคู่มือเพิ่มเติมเกี่ยวกับ และ สำหรับเทคนิคที่ใกล้เคียงกัน
คำถามที่พบบ่อย
ใช้ products.json scrape ร้าน Shopify ทุกแห่งได้ไหม
ร้าน Shopify ส่วนใหญ่จะเปิด endpoint นี้ไว้เป็นค่าเริ่มต้น—จากการทดสอบประมาณ 71% จะคืน JSON ที่ใช้งานได้ บางร้านที่ตั้งค่าเองหรือมีระบบป้องกันเพิ่มเติม (Cloudflare, headless setup) อาจได้ 404 หรือบล็อก request ได้ วิธีเช็กเร็วที่สุดคือเปิด {store-url}/products.json ในเบราว์เซอร์ ถ้าเห็น JSON ก็ใช้ได้
การ scrape ร้าน Shopify ถูกกฎหมายไหม
ข้อมูลสินค้าสาธารณะ เช่น ราคา ชื่อสินค้า รูปภาพ และคำอธิบาย โดยทั่วไปเข้าถึงได้ และบรรทัดฐานทางกฎหมายอย่าง hiQ v. LinkedIn ก็สนับสนุนการ scrape ข้อมูลที่เปิดเผยต่อสาธารณะ แต่ก็ควรตรวจ Terms of Service ของร้านนั้น ๆ และกฎหมายท้องถิ่นเสมอ อย่า scrape ข้อมูลส่วนบุคคลหรือลูกค้า และต้องเคารพ rate limit
scrape ร้าน Shopify ได้กี่สินค้า
ไม่มีข้อจำกัดตายตัวในแง่จำนวนรวม Pagination ด้วย ?limit=250&page= ช่วยให้คุณดึงทั้งแค็ตตาล็อกได้หมด สำหรับร้านใหญ่มาก ๆ (25,000+ สินค้า) ควรใช้ session ซ้ำและเว้นช่วงเวลาเพื่อลดโอกาสโดน rate limit และ /meta.json จะบอกจำนวนสินค้าล่วงหน้าให้รู้ว่าต้องใช้กี่หน้า
ต่างกันอย่างไรระหว่าง products.json กับ Shopify Admin API
/products.json เป็น endpoint สาธารณะ—ไม่ต้องยืนยันตัวตน เป็นข้อมูลสินค้าที่อ่านได้อย่างเดียว ใครก็เข้าถึงได้ ส่วน Admin API ต้องใช้ access token ของเจ้าของร้าน และให้ข้อมูลออเดอร์ จำนวนสต็อก ข้อมูลลูกค้า และสิทธิ์เขียน หากคุณต้องการข้อมูลยอดขายหรือจำนวนสต็อกจริง ๆ ต้องใช้ Admin API (ซึ่งแปลว่าคุณต้องเป็นเจ้าของร้านหรือได้รับอนุญาต)
ไม่ใช้ Python จะ scrape Shopify ได้ไหม
ได้แน่นอน เครื่องมืออย่าง ช่วยให้คุณ scrape ร้าน Shopify ผ่าน Chrome extension ได้โดยไม่ต้องเขียนโค้ด มันจัดการ pagination ให้อัตโนมัติ และ export ไปยัง CSV, Excel, Google Sheets, Airtable หรือ Notion ได้โดยตรง สำหรับนักพัฒนาที่ถนัดภาษาอื่น endpoint /products.json เดิมก็ใช้ได้กับ JavaScript, Ruby, Go—ทุกภาษาที่ส่ง HTTP request และ parse JSON ได้
เรียนรู้เพิ่มเติม