ブログに戻ります

Playwright を使って Shopify スクレイパーを構築する方法

Daniel Kim
Daniel Kim

Lead Scraping Automation Engineer

12-Oct-2026

要約:

  • Shopify スクレイパーはフィールド抽出より前に商品 URL を発見すべきです。 同一オリジンの商品リンクは、テーマのスタイル用クラスよりも耐久性があります。
  • 公開されている構造化商品データで、すべてのスウォッチをクリックしなくてもバリアントを露出できる場合があります。 依存する前に、対象ストアでレスポンスを必ず検証してください。
  • Playwright はストアフロントのデータを読み取りながらブラウザコンテキストを維持できます。 商品および通貨のリクエストはそのコンテキスト内に保持してください。
  • ローカルの例は、バリアント識別子と生の価格値を返します。 通貨換算とストア間マッチングは別タスクとして残ります。
  • 無料で開始可能。 新しい Scrapeless アカウントには Scraping Browser ランタイムが無料で含まれます — app.scrapeless.com でサインアップしてください。

はじめに: 商品カードはすべてのバリアントを記述しない

ストアフロントの商品カードは、複数の購入可能なバリアントを要約していることがよくあります。カードに表示される価格を読むことは発見には有用ですが、すべてのサイズやカラーの価格と在庫状況を確定することはできません。

この Shopify 商品データ抽出チュートリアルでは、Playwright を使って公開ストアフロントを開き、商品リンクを発見し、そのページのブラウザコンテキスト内で構造化されたバリアントデータを読み取ります。例は意図的に 1 商品に限定されています。より大きなカタログジョブを組む前に、返却されるフィールドを検査できます。

Playwright はブラウザを制御し、どのようなレコードが有効とみなされるかは抽出側のコントラクトで決まります。価格下落アラートのワークフローでは、記録された観測値がどのように後段のイベントへと変換されるかを説明しています。

セレクタより前に抽出元を選ぶ

最も有用なソースとは、必要なフィールドを含み、かつ最も安定している公開インターフェースです。

Surface 適した用途 確認すべき制約
公開された商品レスポンス バリアント ID、オプション配列、価格フィールド アクセス性と完全性はストアフロントごとに異なる
埋め込み構造化データ 商品の同定と、説明されたオファー 選択中のオファーだけを要約している場合がある
レンダリングされた商品コントロール サイズやマーケット、購入オプション選択後の状態 ストア固有の調査が必要
商品リンクの URL パターン 発見と重複排除 ヘッドレスなストアフロントは別のルート形状を使用することがある

この例では、観測した /products/<handle> リンクを使用し、その後で商品の公開 .js レスポンスを読み取ります。Shopify の Ajax product interface は、このルートとロケール対応リクエストを文書化しています。そのバリアント配列にはドキュメント化された上限があります。リクエストが成功しただけで、大規模なバリアントカタログを完全にカバーできていると主張してはいけません。

ストアフロントがオファーを露出するためにインタラクションを必要とする場合、そのコントロールを調査し、インタラクション後に商品固有の状態マーカーを待ちます。汎用的な価格セレクタは、誤ってレコメンドカードや分割払い金額、あるいは前のバリアントの価格を拾ってしまう可能性があります。

前提条件とインストール

ローカルの例には Node.js、pnpm、および Playwright の Chromium ランタイムが必要です。

インストールされている Playwright パッケージがサポートする Node.js リリースを使用してください。検証済み環境では Node.js 24 を使用しました。クラウド拡張には、さらに Scrapeless の有効なアカウントと SCRAPELESS_API_KEY 内のサービス API キーが必要です。その認証情報は前提条件であり、ローカルコレクタには不要です。

新しい作業ディレクトリで次のコマンドを実行します:

bash Copy
pnpm add playwright @scrapeless-ai/sdk
pnpm exec playwright install chromium

Playwright の ブラウザライブラリのインストール では、パッケージとブラウザダウンロードを分離しています。JavaScript の例は .mjs ファイルとして保存し、Node.js がそれらを ES モジュールとして扱うようにします。クラウド拡張では Scrapeless Node.js SDK を使用します。

ローカルの Discover-and-Extract コレクタを構築する

このコレクタは、検証済みの商品アンカーを見つけて、構造化レスポンスから各バリアントを返します。

これを shopify.mjs として保存し、node shopify.mjs を実行してください。特定の商品は公開されているサンプルなので、再利用する前に URL とストアポリシーを再確認してください。スクリプトは、別の商品へ黙って切り替えるのではなく、発見用アンカーが存在しないことを報告します。

javascript Copy
import { chromium } from 'playwright';

const browser = await chromium.launch({ headless: true });
try {
  const context = await browser.newContext();
  const page = await context.newPage();
  await page.goto('https://www.taylorstitch.com/', {
    waitUntil: 'domcontentloaded', timeout: 45000
  });

  const result = await page.evaluate(async () => {
    const link = Array.from(document.querySelectorAll('a[href]'))
      .map(a => new URL(a.href))
      .find(u => u.origin === location.origin &&
        /^\/products\/jack-in-valley-plaid-waffle-2610\/?$/.test(u.pathname));
    if (!link) throw new Error('Expected product anchor is absent');

    const root = window.Shopify.routes.root;
    const productResponse = await fetch(link.pathname.replace(/\/$/, '') + '.js');
    const cartResponse = await fetch(root + 'cart.js');
    if (!productResponse.ok || !cartResponse.ok) {
      throw new Error('Product or currency response unavailable');
    }
    const product = await productResponse.json();
    const cart = await cartResponse.json();
    if (!product.id || !Array.isArray(product.variants) || !cart.currency) {
      throw new Error('Incomplete public product response');
    }
    return {
      product_id: String(product.id), title: product.title,
      source_url: link.href, currency: cart.currency,
      observed_at: new Date().toISOString(),
      variants: product.variants.map(v => ({
        variant_id: String(v.id), options: v.options,
        price_raw: v.price, compare_at_price_raw: v.compare_at_price ?? null,
        available: v.available, sku: v.sku ?? null
      }))
    };
  });
  console.log(JSON.stringify(result, null, 2));
} finally {
  await browser.close();
}

domcontentloaded は、すべてのウィジェットが完了したことを保証するものではなく、ナビゲーションの境界線です。検証したホームページでは、その境界線で商品アンカーが露出されています。別のテーマでは、抽出前に実際に必要なリンクや商品コントロールが現れるまで待機してください。

読み取り専用のカートリクエストは、そのブラウザコンテキストにおける提示通貨を特定します。商品を追加したり、チェックアウトを開始したりはしません。商品と通貨の読み取りは依然として異なる瞬間に行われます。それらを原子的な在庫スナップショットだと説明してはいけません。

返却されたバリアントのコントラクトを保持する

その結果は、バリアント配列を持つプロダクトエンベロープであり、完成された競合他社の価格履歴ではありません。

Field Meaning Validation rule
product_id ストアのプロダクト識別子(テキストとしてシリアライズ) 必須
source_url 検出された公開プロダクトURL ストアフロントのホストを維持すること
currency 現在のブラウザコンテキストで報告されている通貨 比較前に既知でなければならない
observed_at コレクターのキャプチャ時刻 変化するフィールドと一緒に保持すること
variant_id ストアのバリアント識別子 親とのリンクを維持すること
options ソースのオプション値 順序と値を保持すること
price_raw レスポンスのネイティブ単位での金額 表示前に単位の意味を確認すること
compare_at_price_raw Null 許容の比較金額 Null はゼロを意味しない
available 公開される購入可能性シグナル 在庫数量ではない
sku ソースの任意のマーチャントSKU 普遍的なプロダクト識別子ではない

チェックしたプロダクトには6つのバリアントが含まれ、コンテキストはUSDを報告していました。これらの観察から、このパスが選択したソースから実際のプロダクトデータを抽出していることはわかりますが、すべてのShopifyストアフロントが同じテーマやアクセス構成を使用していることがわかるわけではありません。

product vocabulary は、IDおよび記述属性と、オファーの変化する商業的フィールドとを区別するのに役立ちます。バリアントを倉庫テーブルの行にフラット化する際には、その境界を維持してください。

Start Scraping with Scrapeless

Scrapeless で Web スクレイピングとオートメーションのワークフローを強化しましょう。
今日サインアップすると $5 の無料クレジット を獲得できます — クレジットカードは不要です。

今すぐ Scrapeless ダッシュボード で無料クレジットを請求しましょう。

カタログ境界を失わずに発見範囲を拡張する

カタログ探索には、明示的な停止ルールと永続的な訪問済みURLセットが必要です。

コレクションベースのスクレイパーでは、実際の次ページリンクまたはストアフロントのドキュメント化されたページネーション機構を確認してください。コレクション探索はプロダクト抽出と分離しておきます。複数のコレクションに現れるアイテムが複数のプロダクトにならないよう、正規化されたプロダクトパスを重複排除します。

実行が承認済みスコープ全体なのか、部分的サンプルなのかを記録します。単一プロダクトの例はサンプルであり、ストアのカタログサイズを確定することはできません。バリアント配列の上限、フィルタされたコレクション、あるいはアクセス不能なページは、出力内のカバレッジ制限として表現されるべきです。

動的な Shopify プロダクトページをスクレイピングするには、構造化ソースが不十分な場合に、正確なオプション選択と可視状態を保持してください。親の最小価格をすべてのバリアント行にコピーしてはいけません。選択されたオファーを自信を持って特定できなくなったところで停止します。

Playwright 用クラウド拡張

Scrapeless Agent Browser は、コレクター側が独自の検証ロジックを保持したまま、Playwright セッションをリモートで実行できます。

ローカルブラウザのホスティングが運用上の負担になってきたら、ドキュメント化された Playwright 接続 を使用してください。SDK がブラウザセッションを作成し、Playwright は返却されたエンドポイントに接続します。

注: 次のクラウド接続には SCRAPELESS_API_KEY に有効な Scrapeless サービス API キーが必要です。ローカル収集の例は単独で実行できます。この資格情報に依存する手順は、クラウドパスをデプロイする前にあなたのアカウント内で実行する必要があります。

javascript Copy
import { Scrapeless } from '@scrapeless-ai/sdk';
import { chromium } from 'playwright';

const client = new Scrapeless();
const { browserWSEndpoint } = await client.browser.create({
  sessionName: 'shopify-public-product',
  sessionTTL: 180,
  proxyCountry: 'US'
});
const browser = await chromium.connectOverCDP(browserWSEndpoint);
try {
  const page = await browser.newPage();
  await page.goto('https://www.taylorstitch.com/', {
    waitUntil: 'domcontentloaded'
  });
  console.log(await page.title());
} finally {
  await browser.close();
}

接続を確認したら、そのセッション内で同じ探索および抽出ルーチンを適用します。国別ルーティングはブラウザパラメータなので、プロキシ設定だけから推測するのではなく、ストアフロントの通貨とロケールを検証してください。Agent Browser と ランタイム料金 を収集スケジュールと照らして評価します。

ソース境界での欠損データのトラブルシュート

欠損データは、保存されたプロダクトレコードになる前に診断すべきです。

Symptom Check Safe disposition
プロダクトアンカーなし 正規パスと現在のコレクション所属 発見を不完全としてマーク
JSON ではなく HTML アクセスチャレンジまたは異なるエンドポイント挙動 抽出を保留
バリアント欠如 レスポンスの上限と選択されたプロダクト カバレッジを不完全としてマーク
通貨変更 ロケール、クッキー、市場選択 別個のコンテキスト系列を開始
空の価格 選択されたオファーとソースフィールドのセマンティクス 不明な値は保持し、決してゼロを挿入しない

作業をスケジューリングする前に、ストアのアクセスルールを確認してください。クローラー除外標準はロボットの希望を記述しており、利用規約と許諾がより広いアクセス境界を規定します。

結論:ディスカバリ、コンテキスト、出力を一体で扱う

Shopify スクレイパーは、Playwright と組み合わせることで、商品ディスカバリに耐久性のあるリンクを使い、バリアント抽出に検証済みの構造化ソースを使うと、保守が容易になります。ブラウザコンテキストを保持し、金額フィールドを明示的に扱い、保存前に結果を検証してください。ページネーション、アクセス制限、対象ストアフロントのバリアント完全性を確認してから、サンプルを超えて拡張しましょう。

Shopify コレクションワークフローを構築する準備はできましたか?

コミュニティに参加して無料プランを取得し、ブラウザベースの EC コレクションに取り組む開発者とつながりましょう: Discord · Telegram。

app.scrapeless.com でサインアップし、承認済みの商品ソースに対して検証済み抽出コントラクトを適用してください。

FAQ

Q: 公開されている Shopify 商品データをスクレイピングすることは合法ですか?

答えは、あなたの法域、ストアの利用規約、アクセス方法、そして利用目的に依存します。それらの条件を確認し、必要に応じて弁護士に相談してください。ワークフローは公開され、許可された商品面に限定しましょう。

Q: Shopify スクレイパーを構築するのにプロキシは必要ですか?

検証済みのローカル例は、プロキシなしでアクセス可能なパブリックソースを読み取ります。クラウド拡張は、ルーティングを一貫させるために proxyCountry を US に設定しますが、通貨およびマーケットの選択には依然として別途の検証が必要です。

Q: スクレイパーは WAF や「Access Denied」ページをどのように扱うべきですか?

結果は商品データではなく、未確認のコレクションとして扱ってください。認可されたクラウドワークフローの場合は、同じセッションで最初にホームページを開き、実際の商品マーカーを待ちます。ストアフロントが要求されたアクセスを許可しない場合は停止してください。

Q: Shopify テーマが DOM クラスをローテーションした場合、何が変わりますか?

ライブのマークアップを再検査し、可能な限り安定した商品 URL または構造化ソースを維持してください。選択された商品およびバリアントを指していることを確認してから、セレクタを更新します。

Q: これは AI エージェントなしで動作させられますか?

はい。ローカルスクリプトは Node.js で直接実行できます。エージェントは別のストアフロントを調査するのに役立ちますが、コレクターの実行には必須ではありません。

Q: 並行実行と商品 URL はどのように扱うべきですか?

まずはストアごとに 1 ワーカーから始め、そのパブリックリンクから発見された正規 URL を使用してください。ストアが並列収集を許可している場合は、ホストごとに 3 ワーカー、あるいはそれより厳しい上限から開始します。バリアントの選択は、正規の商品アイデンティティとは切り離して扱ってください。

Scrapelessでは、適用される法律、規制、およびWebサイトのプライバシーポリシーを厳密に遵守しながら、公開されているデータのみにアクセスします。 このブログのコンテンツは、デモンストレーションのみを目的としており、違法または侵害の活動は含まれません。 このブログまたはサードパーティのリンクからの情報の使用に対するすべての責任を保証せず、放棄します。 スクレイピング活動に従事する前に、法律顧問に相談し、ターゲットウェブサイトの利用規約を確認するか、必要な許可を取得してください。

最も人気のある記事

カタログ