파이썬으로 Shopify 스토어 스크래핑하는 방법

products.json과 효과적인 스크래핑 방법을 활용하여 Shopify 데이터 추출을 간소화하십시오.
1 분 읽기
How to Scrape Shopify blog image

표면적으로 Shopify 스토어는 데이터 추출에서 가장 어려운 과제 중 하나입니다. 아래 제품은 전형적인 Shopify 리스팅을 나타냅니다. 데이터는 거의 최대로 중첩되어 있습니다.

<div class="site-box-content product-holder"><a href="/collections/ready-to-ship/products/the-eira-straight-leg" class="product-item style--one alt color--light   with-secondary-image " data-js-product-item="">

  <div class="box--product-image primary" style="padding-top: 120.00048000192001%"><img src="//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-01_91c15dbe-7412-47b6-8f76-bdb434199203.jpg?v=1731517834&amp;width=640" alt="The Eira - Organic Ecru" srcset="//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-01_91c15dbe-7412-47b6-8f76-bdb434199203.jpg?v=1731517834&amp;width=360 360w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-01_91c15dbe-7412-47b6-8f76-bdb434199203.jpg?v=1731517834&amp;width=420 420w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-01_91c15dbe-7412-47b6-8f76-bdb434199203.jpg?v=1731517834&amp;width=480 480w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-01_91c15dbe-7412-47b6-8f76-bdb434199203.jpg?v=1731517834&amp;width=640 640w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-01_91c15dbe-7412-47b6-8f76-bdb434199203.jpg?v=1731517834&amp;width=840 840w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-01_91c15dbe-7412-47b6-8f76-bdb434199203.jpg?v=1731517834&amp;width=1080 1080w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-01_91c15dbe-7412-47b6-8f76-bdb434199203.jpg?v=1731517834&amp;width=1280 1280w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-01_91c15dbe-7412-47b6-8f76-bdb434199203.jpg?v=1731517834&amp;width=1540 1540w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-01_91c15dbe-7412-47b6-8f76-bdb434199203.jpg?v=1731517834&amp;width=1860 1860w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-01_91c15dbe-7412-47b6-8f76-bdb434199203.jpg?v=1731517834&amp;width=2100 2100w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-01_91c15dbe-7412-47b6-8f76-bdb434199203.jpg?v=1731517834&amp;width=2460 2460w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-01_91c15dbe-7412-47b6-8f76-bdb434199203.jpg?v=1731517834&amp;width=2820 2820w" sizes="(max-width: 768px) 50vw, (max-width: 1024px) and (orientation: landscape) 50vh"amp;width=2820 2820w" sizes="(max-width: 768px) 50vw, (max-width: 1024px) and (orientation: portrait) 50vw, 25vw " loading="lazy" class="lazy lazyloaded" data-ratio="0.8" width="3200" height="4000" onload="this.classList.add('lazyloaded')"><span class="lazy-preloader " aria-hidden="true"><svg class="circular-loader" viewBox="25 25 50 50"><circle class="loader-path" cx="50" cy="50" r="20" fill="none" stroke-width="4"></circle></svg></span></div><div class="box--product-image secondary" style="padding-top: 120.00048000192001%"><img src="//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-02.jpg?v=1731517834&amp;width=640" alt="The Eira - Organic Ecru" srcset="//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-02.jpg?v=1731517834&amp;width=360 360w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-02.jpg?v=1731517834&amp;width=420 420w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-02.jpg?v=1731517834&amp;width=480 480w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-02.jpg?v=1731517834&amp;amp;width=480 480w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-02.jpg?v=1731517834&amp;amp;amp;width=480 480w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-02.jpg?v=1731517834&amp;amp;amp;amp;width=480 480w,//hiutdenim.co.uk/cdn/shop/amp;width=480 480w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-02.jpg?v=1731517834&amp;width=640 640w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-02.jpg?v=1731517834&amp;width=840 840w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-02.jpg?v=1731517834&amp;width=1080 1080w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-02.jpg?v=1731517834&amp;width=1280 1280w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-02.jpg?v=1731517834&amp;width=1540 1540w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-02.jpg?v=1731517834&amp;width=1860 1860w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-02.jpg?v=1731517834&amp;width=2100 2100w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-02.jpg?v=1731517834&amp;width=2460 2460w,//hiutdenim.co.uk/cdn/shop/files/Hiut-EiraEcru-02.jpg?v=1731517834&amp;width=2820 2820w" sizes="(max-width: 768px) 50vw, (max-width: 1024px) and (orientation: portrait) 50vw, 25vw " loading="lazy" class="lazy lazyloaded" data-ratio="0.8" width="3200" height="4000" onload="this.classList.add('lazyloaded')"></div><div class="caption">

    <div>
      <span class="title"><span class="underline-animation">The Eira - Organic Ecru</span></span>
      <span class="price text-size--smaller"><span style="display:flex;flex-direction:row">$285.00</span></span>

    </div><quick-view-product class="quick-add-to-cart">
          <div class="quick-add-to-cart-button">
            <button class="product__add-to-cart" data-href="/products/the-eira-straight-leg" tabindex="-1">
              <span class="visually-hidden">장바구니에 담기</span>
              <span class="add-to-cart__text" style="height:26px" role="img"><svg width="22" height="26" viewBox="0 0 22 26" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M6.57058 6.64336H4.49919C3.0296 6.64336 1.81555 7.78963 1.7323 9.25573L1.00454 22.0739C0.914352 23.6625 2.17916 25 3.77143 25H18.2286C19.8208 25 21.0856 23.6625 20.9955 22.0739L20.2677 9.25573C20.1844 7.78962 18.9704 6.64336 17.5008 6.64336H15.4294M6.57058 6.64336H15.4294M6.57058 6.64336V4.69231C6.57058 2.6531 8.22494 1 10.2657 1H11.7343C13.775 1 15.4294 2.6531 15.4294 4.69231V6.64336" stroke="var(--main-text)" style="fill:none!important" stroke-width="1.75"></path><path d="M10.0801 12H12.0801V20H10.0801V12Z" fill="var(--main-text)" style="stroke:none!important"></path><path d="M15.0801 15V17L7.08008 17L7.08008 15L15.0801 15Z" fill="var(--main-text)" style="stroke:none!important"></path></svg></span><span class="lazy-preloader add-to-cart__preloader" aria-hidden="true"><svg class="circular-loader" viewBox="25 25 50 50"><circle class="loader-path" cx="50" cy="50" r="20" fill="none" stroke-width="4"></circle></svg></span></button>
          </div>
        </quick-view-product></div><div class="product-badges-holder"></div></a></div>

위 HTML에서 데이터를 추출하는 것이 불가능한 것은 아니지만, 더 쉬운 방법이 있습니다.

Shopify 랜딩 페이지

https://hiutdenim.co.uk/의 랜딩 페이지에는 일부 제품 정보가 포함되어 있지만, 상대적으로 제한적입니다. 충분히 아래로 스크롤하면 해당 정보를 확인할 수 있습니다.

Front Page of a Shopify Store

첫눈에 보기에 모든 섹션의 링크를 하나하나 추출한 후, 각각의 페이지를 불러와 파싱해야 할 것처럼 보입니다. Shopify 스토어는 독특한 페이지 레이아웃으로 인해전자상거래 스크래핑의전통적인 방식을 따르지 않습니다. 하지만 다른 방법이 있습니다.

Shopify JSON 페이지

제목을 제대로 읽으셨습니다. 기본적으로 모든 스토어 상품을 JSON 객체로 가져올 수 있습니다.BeautifulSoup이나Selenium 같은 도구도 필요 없습니다.

URL에/products.json만추가하면 됩니다. 모든 Shopify 사이트는products.json파일을 기반으로 구축됩니다.

Shopify JSON Page

이 콘텐츠를 요청할 수 있다면(가능합니다), 원하는 모든 데이터를 얻을 수 있습니다. 데이터를 확보한 후에는 어떤 데이터를 유지할지 결정하기만 하면 됩니다.지금까지 사용해 온 사이트에서 이를 직접 확인해 볼 수 있습니다.

파이썬으로 Shopify 스크래핑하기

이제 우리가 무엇을 찾고 있는지 알았으니, 이 어려운 작업이 훨씬 덜 까다로워집니다. JSON 데이터만 다루기 때문에 설치해야 할 의존성은Python Requests 하나뿐입니다.

pip install requests

개별 함수

개별 코드 조각을 살펴보겠습니다. 스크레이퍼를 구성하는 세 개의 분리된 블록이 있습니다.

가장 중요한 함수입니다. 실제 스크래핑 로직을 수행합니다.

def scrape_shopify(url, retries=2):
    """shopify 스토어 스크래핑"""
    json_url = f"{url}products.json"
    items = []
    success = False
    while not success and retries > 0:
        response = requests.get(json_url)
        try:
            response.raise_for_status()
            products = response.json()["products"]
            for product in products:
                product_data = {
                    "title": product["title"],
                    "tags": product["tags"],
                    "id": product["id"],
                    "variants": product["variants"],
                    "images": product["images"],
                    "options": product["options"]
                }
                items.append(product_data)            
            success = True
        except requests.RequestException as e:
            print(f"요청 중 오류: {e}, {json_url} 가져오기 실패")
        except KeyError as key_error:
            print(f"json 파싱 실패: {key_error}")
        except json.JSONDecodeError as e:
            print(f"json 오류: {e}")
        except Exception as e:
            print(f"예상치 못한 오류: {e}")
        retries-=1
        print(f"남은 재시도 횟수: ", retries)
    return items
  • 먼저,products.json을우리 URL에 추가합니다:json_url = f"{url}products.json".
  • 빈 배열items를 초기화합니다. 항목을 스크래핑하면서 이 배열에 추가할 것입니다. 스크래핑이 완료되면 파싱된 항목 배열을 반환합니다.
  • 정상적인 응답을 받는 한,"products"키를 통해 모든 제품을 가져옵니다.
  • 각 제품에서 다양한 데이터를 추출하여product_data라는딕셔너리를 생성합니다.
  • product_data는배열에 추가됩니다.
  • 이 과정은 페이지의 모든 제품을 파싱할 때까지 반복됩니다.

이제 스크래핑을 수행하고 제품 배열을 반환하는 함수를 갖게 되었습니다. 이제 이 제품 배열을 받아 파일을 작성하는 함수가 필요합니다. 여기서 CSV를 사용할 수도 있지만, 이 구조는 상당히 중첩되어 있으므로 JSON을 사용하겠습니다. JSON은 이후 사용 및 분석을 위해 더 유연한 데이터 구조를 지원합니다.

def json2file(json_data, filename):
    """json 데이터를 파일에 저장"""
    try:
        with open(filename, "w", encoding="utf-8") as file:
            json.dump(json_data, file, indent=4)
            print(f"데이터 저장 성공: {filename}")
    except Exception as e:
        print(f"{filename}에 json 데이터 쓰기 실패, 오류: {e}")

이것이 우리가 사용할 실제 코드입니다. 이제 스크레이퍼를 실행할 메인 블록을 생성합니다.

if __name__ == "__main__":
    shop_url = "https://hiutdenim.co.uk/"
    items = scrape_shopify(shop_url)

    json2file(items, "output.json")

모든 것을 합치기

모든 것을 합치면 스크레이퍼는 이렇게 보입니다. 복잡해 보였던 파싱 프로젝트가 이제 약 50줄의 코드로만 구성된 완전한 기능의 스크레이퍼가 되었습니다.

import requests
import json

def json2file(json_data, filename):
    """json 데이터를 파일로 저장"""
    try:
        with open(filename, "w", encoding="utf-8") as file:
            json.dump(json_data, file, indent=4)
            print(f"데이터 저장 성공: {filename}")
    except Exception as e:
        print(f"{filename}에 json 데이터 쓰기 실패, 오류: {e}")

def scrape_shopify(url, retries=2):
    """shopify 스토어 스크래핑"""
    json_url = f"{url}products.json"
    items = []
    success = False
    while not success and retries > 0:
        response = requests.get(json_url)
        try:
            response.raise_for_status()
            products = response.json()["products"]
            for product in products:
                product_data = {
                    "title": product["title"],
                    "tags": product["tags"],
                    "id": product["id"],
                    "variants": product["variants"],
                    "images": product["images"],
                    "options": product["options"]
                }
                items.append(product_data)            
            success = True
        except requests.RequestException as e:
            print(f"요청 중 오류: {e}, {json_url} 가져오기 실패")
        except KeyError as key_error:
            print(f"json 파싱 실패: {key_error}")
        except json.JSONDecodeError as e:
            print(f"json 오류: {e}")
        except Exception as e:
            print(f"예상치 못한 오류: {e}")
        retries-=1
    return items


if __name__ == "__main__":
    shop_url = "https://hiutdenim.co.uk/"
    items = scrape_shopify(shop_url)

    json2file(items, "output.json")

반환 데이터

데이터는 JSON 객체 배열로 반환됩니다. 각 상품은 변형(variant)이미지 목록을 포함합니다. 이러한 정보는 CSV로 정확하게 표현하기 매우 어렵습니다. 아래 스니펫은 스크래핑한 단일 상품의 예시입니다.

{
        "title": "The Valerie - Organic Denim",
        "tags": [
            "The Valerie",
            "Women"
        ],
        "id": 14874183401848,
        "variants": [
            {
                "id": 54902462808440,
                "title": "UK10-29 / 30",
                "option1": "UK10-29",
                "option2": "30",
                "option3": null,
                "sku": null,
                "requires_shipping": true,
                "taxable": true,
                "featured_image": null,
                "available": true,
                "price": "220.00",
                "grams": 0,
                "compare_at_price": null,
                "position": 1,
                "product_id": 14874183401848,
                "created_at": "2026-01-21T14:04:58+00:00",
                "updated_at": "2026-02-12T17:17:54+00:00"
            },
            {
                "id": 54902462939512,
                "title": "UK12-30 / 32",
                "option1": "UK12-30",
                "option2": "32",
                "option3": null,
                "sku": null,
                "requires_shipping": true,
                "taxable": true,
                "featured_image": null,
                "available": true,
                "price": "220.00",
                "grams": 0,
                "compare_at_price": null,
                "position": 2,
                "product_id": 14874183401848,
                "created_at": "2026-01-21T14:04:58+00:00",
                "updated_at": "2026-02-12T17:17:54+00:00"
            },
            {
                "id": 54902463070584,
                "title": "UK14-32 / 28",
                "option1": "UK14-32",
                "option2": "28",
                "option3": null,
                "sku": null,
                "requires_shipping": true,
                "taxable": true,
                "featured_image": null,
                "available": true,
                "price": "220.00",
                "grams": 0,
                "compare_at_price": null,
                "position": 3,
                "product_id": 14874183401848,
                "created_at": "2026-01-21T14:04:58+00:00",
                "업데이트 시간": "2026-02-12T17:17:54+00:00"
            },
            {
                "id": 54902463496568,
                "title": "UK18-36 / 30",
                "option1": "UK18-36",
                "option2": "30",
                "option3": null,
                "sku": null,
                "requires_shipping": true,
                "taxable": true,
                "featured_image": null,
                "available": true,
                "price": "220.00",
                "grams": 0,
                "비교가격": null,
                "위치": 4,
                "제품ID": 14874183401848,
                "생성일시": "2026-01-21T14:04:58+00:00",
                "업데이트 시간": "2026-02-12T17:17:54+00:00"
            }
        ],
        "images": [
            {
                "id": 31828166443078,
                "created_at": "2024-06-17T12:05:49+01:00",
                "position": 1,
                "updated_at": "2024-06-17T12:05:50+01:00",
                "product_id": 14874183401848,
                "variant_ids": [],
                "src": "https://cdn.shopify.com/s/files/1/0065/4242/files/HDC_0723_JapanInd_Valerie_45_3_c547ba8a-681b-4486-8cd7-884000e43302.jpg?v=1718622350",
                "width": 4000,
                "height": 4000
            },
            {
                "id": 31828166541382,
                "created_at": "2024-06-17T12:05:49+01:00",
                "position": 2,
                "updated_at": "2024-06-17T12:05:51+01:00",
                "product_id": 14874183401848,
                "variant_ids": [],
                "src": "https://cdn.shopify.com/s/files/1/0065/4242/files/HDC_0723_JapanInd_Valerie_Back_2_5909adb3-c2ab-4810-8b66-a486e8d827a8.jpg?v=1718622351",
                "width": 4000,
                "height": 4000
            },
            {
                "id": 31828166508614,
                "created_at": "2024-06-17T12:05:49+01:00",
                "position": 3,
                "updated_at": "2024-06-17T12:05:51+01:00",
                "product_id": 14874183401848,
                "variant_ids": [],
                "src": "https://cdn.shopify.com/s/files/1/0065/4242/files/HDC_0723_JapanInd_Valerie_Front_3_4316907a-9fd8-4649-894c-4028877370e1.jpg?v=1718622351",
                "width": 4000,
                "height": 4000
            },
            {
                "id": 31828166475846,
                "created_at": "2024-06-17T12:05:49+01:00",
                "position": 4,
                "updated_at": "2024-06-17T12:05:51+01:00",
                "product_id": 14874183401848,
                "variant_ids": [],
                "src": "https://cdn.shopify.com/s/files/1/0065/4242/files/HDC_0723_JapanInd_Valerie_Side_2_ea21477b-c1ba-4c8a-b75e-75c6427b4977.jpg?v=1718622351",
                "width": 4000,
                "height": 4000
            }
        ],
        "options": [
            {
                "name": "허리",
                "position": 1,
                "values": [
                    "UK10-29",
                    "UK12-30",
                    "UK14-32",
                    "UK18-36"
                ]
            },
            {
                "name": "다리 길이",
                "position": 2,
                "values": [
                    "30",
                    "32",
                    "28"
                ]
            }
        ]
    },

고급 기법

세상은 완벽하지 않으며, 위 스크레이퍼로 어려움을 겪을 수도 있습니다. 여러 페이지를 스크레이핑해야 할 수도 있고, 때로는 스크레이퍼가 차단될 수도 있습니다.

페이지네이션

대규모 스토어를 스크래핑할 때 페이지가 분할된 결과를 가진 스토어를 자주 마주치게 됩니다. 페이지 분할을 처리하려면 먼저 페이지당 최대 결과 수를 확인해야 합니다. 결과 페이지를 제어하기 위해 다음과 같은 쿼리 매개변수를 추가할 수 있습니다: page=<PAGE_NUMBER>

스크래핑 함수를 약간 수정하여 URL과 페이지 번호를 받아 처리할 수 있습니다.

def scrape_shopify(url, retries=2):
    """shopify 스토어 스크래핑"""
    json_url = f"{url}products.json"

그런 다음 이러한 변경 사항을 반영하도록 메인 함수를 조정합니다.

if __name__ == "__main__":
    shop_url = "https://www.allbirds.com/"
    PAGES = 3

    for page in range(PAGES):
        items = scrape_shopify(shop_url, page=page+1)

        json2file(items, f"page{page}output.json")

프록시 통합

스크레이퍼가 차단되는 것을 방지하기 위해프록시 서비스를사용해야 할 때가 있습니다.Shopify 프록시를 사용하면 자격 증명을 포함한 URL을 생성하는 것만큼 간단합니다.

PROXY_URL = "http://brd-customer-<YOUR-USERNAME>-zone-<YOUR-ZONE>:<YOUR-PASSWORD>@brd.superproxy.io:33335"
proxies = {
    "http": PROXY_URL,
    "https": PROXY_URL
}
response = requests.get(json_url, proxies=proxies, verify="brd.crt")

Bright Data의 다른 솔루션

Bright Data는 복잡한 스크레이퍼를 처음부터 구축할 필요 없이 사용할 수 있는 강력한 턴키 솔루션을 제공합니다. 원활한 데이터 추출을 위해 완전히 최적화된 Shopify 스크레이퍼를 사용하거나, 다양한 형식으로 제공되는 방대한 사전 수집 데이터셋 라이브러리에 즉시 접근하여 프로젝트를 빠르게 시작하세요.

결론

Shopify 스토어 스크래핑은 불가능한 작업이 아닙니다.products.json을 활용한 API를 간단히 활용하면 방대한 상세 상품 데이터를 신속하게 수집할 수 있습니다. HTML 파서조차 필요하지 않습니다! 원하신다면 당사의 사전 제작된 스크래퍼 중 하나로 개발 시간을 단축하거나, 당사의 데이터셋으로 즉시 작업을 시작할 수 있습니다.

모든 제품에 무료 체험판이 제공됩니다. 지금 바로 가입하세요!