Python으로 Shopify 스크래핑하기: 시장 조사를 자동화하는 방법

최종 업데이트: April 16, 2026

Shopify의 /products.json 엔드포인트는 이커머스 데이터 업계에서 거의 다들 아는 비밀 같은 존재입니다. Shopify 스토어 URL 뒤에 이 경로만 붙이면 API 키나 인증 없이, 복잡한 HTML을 일일이 파고들 필요도 없이 구조화된 JSON 데이터를 바로 받아올 수 있습니다.

저는 팀에서 일하면서 사람들이 웹에서 데이터를 어떻게 뽑아내는지 늘 관심 있게 보고 있습니다. 그리고 Shopify 스크래핑은 정말 자주 등장하는 주제예요. 경쟁사 가격을 따라가려는 세일즈 팀, 상품 카탈로그를 비교하려는 이커머스 운영팀, 새로운 공급업체를 찾는 구매 담당자까지 쓰임새가 아주 다양하죠. Shopify에는 가 있고, 미국 이커머스 시장의 약 를 차지하니, 수집할 수 있는 상품 데이터 규모도 상당합니다.

이 가이드에서는 엔드포인트가 어떤 데이터를 돌려주는지부터 시작해서, 수천 개 상품을 페이지네이션으로 가져오는 방법, 차단되지 않도록 속도 제한을 다루는 법, 그리고 pandas로 Shopify의 중첩 JSON을 깔끔한 CSV 또는 Excel 파일로 평탄화하는 방법까지 전 과정을 차근차근 다룹니다. 또 다른 글에서는 잘 다루지 않는 엔드포인트(/collections.json, /meta.json)도 함께 소개하고, 파이썬 없이 바로 쓰고 싶은 분들을 위한 노코드 대안도 같이 보여드리겠습니다.

Shopify의 /products.json 엔드포인트란 무엇이며, 왜 스크래핑이 쉬운가?

모든 Shopify 스토어에는 {store-url}/products.json이라는 공개 엔드포인트가 있고, 여기서 구조화된 상품 데이터를 받을 수 있습니다. API 키도, OAuth도, 별도 인증도 필요 없습니다. 스토어 URL 뒤에 /products.json만 붙이면 카탈로그 전체의 JSON 배열이 그대로 내려옵니다.

지금 바로 확인해보세요. 브라우저에서 또는 을 열어보면 상품명, 가격, 변형, 이미지, 태그 등이 정리된 JSON으로 보일 겁니다.

반대로 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를 스크래핑해야 할까? 핵심 비즈니스 활용 사례

굳이 왜 하느냐고요? 답은 투자 대비 효과(ROI)입니다. 가 이미 경쟁 정보 분석을 위해 자동 가격 스크래핑을 쓰고 있고, 이는 2020년의 34%에서 크게 늘어난 수치입니다. 또 연구에 따르면 가 나온다고 합니다. 이건 그냥 숫자가 아니라 실제 돈입니다.

제가 가장 자주 보는 활용 사례는 다음과 같습니다.

This paragraph contains content that cannot be parsed and has been skipped.

이 작업에는 Python이 정말 잘 맞습니다. 가 주 언어로 Python을 쓰고 있고, requests(HTTP), pandas(데이터 처리), httpx(비동기) 같은 생태계 덕분에 “URL만 있다”에서 “스프레드시트가 있다”까지 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 슬러그—상품 페이지 링크는 {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객체 배열(아래 이미지 필드 참고)카탈로그 및 시각 분석용 이미지 URL
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 엔드포인트에서 제거되었습니다. 공개적으로 얻을 수 있는 재고 지표는 각 변형의 불리언 available(true 또는 false)뿐입니다. 실제 재고 수량을 보려면 스토어 소유자 자격 증명이 필요한 인증된 Admin API가 필요합니다.

스크래핑 코드를 짜기 전에 이 표를 보고 어떤 필드가 필요한지 먼저 정하세요. 가격 모니터링이 목적이라면 variants[].price, variants[].compare_at_price, variants[].available이 중요합니다. 리드 생성이 목적이라면 vendor, product_type, tags에 집중하면 됩니다. 용도에 맞게 필터링하면 CSV도 훨씬 깔끔해집니다.

products.json을 넘어서: 컬렉션, 메타, 기타 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 — 카테고리별 상품

특정 컬렉션으로 필터링된 상품을 반환합니다. 구조는 /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 키)
재고 수량(자신의 스토어만)Admin API /inventory_levels.json

커뮤니티에서 자주 나오는 질문인 “경쟁사가 몇 개를 팔았는지 스크래핑할 수 있나요?”에 대한 답은 간단합니다. 공개 엔드포인트로는 불가능합니다. 판매 데이터와 실제 재고 수량은 인증된 Admin API가 있어야 볼 수 있고, 즉 스토어 소유자 권한이 있어야 합니다. 공개 엔드포인트는 상품 카탈로그 데이터만 제공합니다.

shopify-data-access-methods.webp

Python으로 Shopify 스크래핑하는 방법: 단계별 설정

  • 난이도: 초급
  • 예상 소요 시간: 약 15분(설정 + 첫 스크래핑)
  • 준비물: Python 3.11 이상, pip, 터미널, 그리고 스크래핑할 Shopify 스토어 URL

1단계: Python과 필요한 라이브러리 설치

Python 3.11 이상이 설치되어 있는지 먼저 확인하세요(pandas 3.0.x는 이를 요구합니다). 그런 다음 필요한 두 라이브러리를 설치합니다.

1pip install requests pandas

Excel로 내보내려면 이것도 추가하세요.

1pip install openpyxl

스크립트 상단에는 아래 import를 넣습니다.

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

실행할 때 import 에러가 없어야 합니다. 만약 pandas에서 버전 오류가 난다면 Python을 3.12로 업그레이드하세요.

2단계: /products.json에서 상품 데이터 가져오기

아래는 스토어 URL을 받아 엔드포인트를 호출하고, 파싱된 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이라서, 명시적으로 250으로 설정하면 요청 수를 최대 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 딕셔너리 리스트로 받았다면, 이제 필요한 필드만 추출하면 됩니다. 아래 예시는 가격 모니터링에 가장 흔히 쓰는 필드를 가져오는 코드입니다.

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행(가격 모니터링 및 재고 추적에 가장 적합)

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: 상품 요약별 1행(카탈로그 개요에 가장 적합)

1def summarize_products(products):
2    """변형 전체의 최소/최대 가격을 포함해 상품당 1행으로 요약합니다."""
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 내보내기(Excel이 특수문자를 잘 처리하도록 utf-8-sig 사용)
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 라이브러리를 서비스 계정과 함께 사용할 수 있지만, 솔직히 대부분의 경우 CSV로 저장한 뒤 Google Drive에 올리는 쪽이 더 빠르고 간단합니다.

운영 환경에 맞는 Python 스크래핑: 속도 제한, 재시도, 차단 회피

기본 스크립트는 작은 스토어에서는 잘 작동합니다. 하지만 상품이 5,000개 이상이거나 여러 스토어를 연속으로 스크래핑하면 얘기가 달라집니다.

Shopify의 속도 제한과 차단 동작 이해하기

Shopify의 공개 JSON 엔드포인트는 Admin API의 leaky bucket 모델처럼 공식 문서화된 속도 제한은 없지만, 실제 테스트 결과는 다음과 같습니다.

  • 안전한 속도: 스토어당 초당 약 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
4> This paragraph contains content that cannot be parsed and has been skipped.
5`Retry` 설정은 지수 백오프로 429 응답을 자동 처리합니다. `backoff_factor=1`이면 재시도 사이의 대기 시간이 0.5초 → 1초 → 2초 → 4초 → 8초로 늘어납니다. `requests.Session()`을 재사용하면 연결 풀링도 적용되어 같은 도메인에 여러 번 요청할 때 오버헤드가 줄어듭니다.
6**User-Agent 순환**: 여러 스토어를 스크래핑한다면 3~5개의 현실적인 브라우저 User-Agent 문자열을 번갈아 사용하는 게 좋습니다. 속이기 위해서가 아니라, 매 요청마다 똑같은 헤더를 보내는 봇처럼 보이지 않게 하려는 목적입니다.
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" allowFullScreen></iframe>
8## CSV 내보내기까지 포함한 완성형 Shopify 스크래핑 Python 스크립트
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    """/products.json을 통해 Shopify 스토어의 모든 상품을 스크래핑합니다."""
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초 정도 걸리고, 변형 단위로 약 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 없이 2번 클릭으로 Shopify 스크래핑하기: Thunderbit 노코드 대안

모든 사람이 Python 설치, import 오류 해결, 스크래핑 스크립트 유지보수를 하고 싶어 하는 건 아닙니다. 내일 아침까지 경쟁사 가격이 필요한 세일즈 담당자라면 Python은 좀 과할 수 있죠.

그래서 저희는 Chrome 확장 프로그램으로 작동하는 AI 웹 스크래퍼인 를 만들었습니다. 코드도, API 키도, 환경 설정도 필요 없습니다.

Thunderbit가 Shopify 스토어를 스크래핑하는 방식

Thunderbit에는 Shopify 상품 페이지에 맞게 미리 세팅된 전용 Shopify Scraper 템플릿이 있습니다. 를 설치한 뒤 Shopify 스토어로 가서 "Scrape"를 누르면 됩니다. 템플릿이 상품명, 설명, 가격, 변형 정보, 이미지, 공급업체 정보를 자동으로 뽑아줍니다.

템플릿이 완벽하게 맞지 않더라도(커스텀 테마, 특이한 레이아웃 등) Thunderbit의 AI 필드 추천 기능이 페이지를 읽고 열 이름을 자동으로 만들어줍니다. 이 열들은 직접 수정할 수도 있고, "compare_at_price가 설정된 상품만 추출" 같은 식으로 조건도 줄 수 있습니다.

Python 스크립트가 하던 일을 그대로 대신하는 기능들은 다음과 같습니다.

  • 서브페이지 스크래핑: 각 상품 상세 페이지를 자동으로 방문해 전체 설명, 리뷰, 변형 정보를 표에 보강합니다. Python에서 여러 페이지를 돌며 처리하는 것과 비슷하지만 코드가 필요 없습니다.
  • 자동 페이지네이션: 클릭형 페이지네이션과 무한 스크롤을 별도 설정 없이 처리합니다.
  • 예약 스크래핑: 정기적인 가격 모니터링을 위해 "매주 월요일 오전 9시" 같은 반복 작업을 설정할 수 있습니다. cron이나 서버가 필요 없습니다.
  • 무료 내보내기: 모든 플랜에서 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 작업 + 호스팅내장 스케줄러
속도 제한 대응재시도/백오프 직접 구현자동 처리
적합한 대상개발자, 대규모 데이터 파이프라인비즈니스 사용자, 빠른 추출, 반복 모니터링

완전한 제어가 필요하거나 더 큰 데이터 파이프라인에 넣어야 한다면 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"])로 빠르게 정리할 수 있습니다.
  • 가격은 계산 전에 float로 변환하세요. Shopify는 가격을 숫자가 아니라 문자열("185.00")로 반환합니다.
  • 엔드포인트 변경을 모니터링하세요: /products.json은 오랫동안 안정적이었지만, 이론적으로 Shopify가 제한할 가능성은 있습니다. 스크래퍼가 갑자기 404를 반환하면 먼저 스토어를 직접 확인하세요.

더 탄탄한 스크래퍼를 만드는 방법은 가이드를 참고하세요.

Shopify 스크래핑 시 법적·윤리적 고려사항

짧지만 중요한 부분입니다.

/products.json 엔드포인트는 누구나 볼 수 있는 상품 데이터를 제공합니다. 즉, 방문자가 스토어를 둘러볼 때 보는 정보와 같아요. Shopify 이용약관에는 “서비스”에 접근할 때 “자동화된 수단”을 쓰지 말라는 문구가 있지만, 이는 플랫폼 자체(관리 대시보드, 결제)를 가리키는 것으로, 공개 스토어프론트 데이터까지 포함한다고 보긴 어렵습니다. 2026년 4월 기준 Shopify 관련 스크래핑 소송은 제기된 바 없습니다.

공개 데이터 스크래핑을 지지하는 주요 판례도 있습니다. hiQ v. LinkedIn 사건은 공개적으로 접근 가능한 데이터의 스크래핑이 CFAA를 위반하지 않는다고 봤고, Meta v. Bright Data(2024)는 약관 제한이 로그인 상태에서만 적용된다고 판시했습니다.

모범 사례:

  • 공개적으로 접근 가능한 상품 데이터만 스크래핑하기
  • 개인 정보나 고객 데이터는 스크래핑하지 않기
  • robots.txt와 속도 제한 지키기
  • 개인 정보를 다루는 경우 GDPR/CCPA 준수하기(상품 카탈로그 데이터는 비개인 정보)
  • 명확한 User-Agent 문자열로 자신을 식별하기
  • 자신의 Shopify 스토어를 Admin API로 스크래핑하는 것은 언제나 문제없음

더 자세한 내용은 글에서 확인할 수 있습니다.

결론 및 핵심 요약

Shopify의 공개 /products.json 엔드포인트는 이커머스 데이터 추출을 놀랄 만큼 쉽게 만들어줍니다. 워크플로는 단순합니다. /products.json을 붙이고 → Python으로 가져오고 → ?limit=250&page=로 페이지네이션하고 → pandas로 평탄화한 뒤 → CSV 또는 Excel로 내보내면 됩니다.

이 가이드가 다른 글보다 더 자세히 다룬 부분은 다음과 같습니다.

  • 완전한 필드 참고표: 코드 한 줄 쓰기 전에 어떤 데이터가 있는지 정확히 파악 가능(상품, 변형, 이미지 전반 40개+ 필드)
  • 추가 엔드포인트: /collections.json/meta.json으로 카테고리 수준 인사이트와 스토어 메타데이터 확보
  • 운영 가능한 기법: 세션 재사용, 지수 백오프, User-Agent 헤더, ?limit=250으로 실제 환경의 속도 제한 대응
  • 올바른 CSV/Excel 내보내기: 원시 JSON 덤프가 아니라 pandas로 변형 단위 데이터를 평탄화
  • 노코드 대안: 코드보다 속도가 중요하다면

단발성 또는 반복적인 Shopify 데이터 추출을 코드 없이 하고 싶다면 를 사용해보세요. Shopify Scraper 템플릿이 페이지네이션부터 내보내기까지 모두 처리합니다. 여러 스토어에서 대규모로 커스텀 데이터 파이프라인을 만들고 싶다면, 이 가이드의 Python 스크립트가 완전한 제어권을 제공합니다.

영상 튜토리얼은 에서 확인할 수 있고, 관련 기술로는 가이드를 참고하실 수 있습니다.

Shopify 스크래핑을 위해 Thunderbit 사용해보기

자주 묻는 질문

products.json으로 어떤 Shopify 스토어든 스크래핑할 수 있나요?

대부분의 Shopify 스토어는 기본적으로 이 엔드포인트를 제공합니다. 테스트 결과 약 71%에서 유효한 JSON이 반환됐습니다. 다만 커스텀 설정이나 Cloudflare, 헤드리스 구조 같은 추가 보안층이 있는 스토어는 404를 반환하거나 요청을 차단할 수 있습니다. 빠른 확인 방법은 {store-url}/products.json을 브라우저에서 직접 열어보는 것입니다. JSON이 보이면 정상입니다.

Shopify 스토어를 스크래핑하는 것은 합법인가요?

가격, 상품명, 이미지, 설명처럼 공개 상품 데이터는 일반적으로 접근 가능하며, hiQ v. LinkedIn 같은 판례도 공개 정보 스크래핑을 지지합니다. 다만 각 스토어의 이용약관과 현지 법률은 반드시 확인하세요. 개인 정보나 고객 데이터는 수집하지 말고, 속도 제한도 지켜야 합니다.

Shopify 스토어에서 몇 개까지 상품을 스크래핑할 수 있나요?

총 개수에 대한 하드 리미트는 없습니다. ?limit=250&page=로 페이지네이션하면 전체 카탈로그를 모두 가져올 수 있습니다. 상품이 25,000개 이상인 매우 큰 스토어의 경우에는 세션 재사용과 지연을 사용해 속도 제한을 피하세요. /meta.json 엔드포인트는 정확한 상품 수를 미리 알려주므로 페이지 수를 예측하는 데 도움이 됩니다.

products.json과 Shopify Admin API의 차이는 무엇인가요?

/products.json은 공개 엔드포인트로, 인증 없이 누구나 읽기 전용 상품 데이터를 볼 수 있습니다. 반면 Admin API는 스토어 소유자의 접근 토큰이 필요하며, 주문·재고 수량·고객 데이터·쓰기 권한을 제공합니다. 판매 데이터나 실제 재고 수량이 필요하다면 Admin API 접근이 필요합니다(즉, 스토어 소유자이거나 허가를 받아야 합니다).

Python 없이 Shopify를 스크래핑할 수 있나요?

물론입니다. 같은 도구를 사용하면 Chrome 확장 프로그램으로 코딩 없이 Shopify 스토어를 스크래핑할 수 있습니다. 페이지네이션도 자동으로 처리하고 CSV, Excel, Google Sheets, Airtable, Notion으로 바로 내보낼 수 있습니다. 다른 언어를 선호하는 개발자라면 JavaScript, Ruby, Go 등 HTTP 요청과 JSON 파싱이 가능한 어떤 언어로도 동일한 /products.json 엔드포인트를 사용할 수 있습니다.

더 알아보기

Ke
Ke
CTO @ Thunderbit. Ke is the person everyone pings when data gets messy. He's spent his career turning tedious, repetitive work into quiet little automations that just run. If you've ever wished a spreadsheet could fill itself in, Ke has probably already built the thing that does it.
목차

Thunderbit 사용해보기

리드와 기타 데이터를 단 2번 클릭으로 수집하세요. AI로 구동됩니다.

Thunderbit 받기 무료예요
AI로 데이터 추출하기
Google Sheets, Airtable, Notion으로 데이터를 쉽게 옮기세요
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week