Walmart製品データのスクレイピング方法: JSON、地理的価格、ブロック

Walmartには公開APIがなく、すべてのページを個別にカスタマイズし、スクレイパーを押して保持するCAPTCHAで制限しています。しかし、Next.jsのJSONを使用すれば、IPが通過すれば、クリーンで構造化されたデータを手に入れることができます。ここにその全方法があります。

Walmartは世界最大の小売業者であり、その価格は経済のライブシグナルとなっていますが、Walmartの公開APIは存在しません。だから人々はスクレイピングを行います。良いニュース: WalmartはNext.jsサイトであり、すべての製品ページにはすでに解析された完全でクリーンなデータを含む単一のJSONブロブがあります。悪いニュース: データセンターIPはそのJSONを見る前に押して保持するCAPTCHAに直面します。このガイドでは信頼性のある方法をカバーしています — スタイル化されたHTMLではなくハイドレーションJSONを読み、適切なIPでHUMANのボット防御を突破し、店舗レベルの地理的価格を取得します。

タグの解析をやめてください。__NEXT_DATA__ JSONを読み取ってください

ほとんどのチュートリアルは、タイトル用にh1を、価格用にspanを見つけるように教えます。それはWalmartがクラス名を頻繁に変更するまで機能します。耐久性のあるアプローチ: Walmartはid="__NEXT_DATA__"を持つスクリプトタグからReactをレンダリングし、製品モデル全体をJSONとして含んでいます。それを一度取得すれば、すべてのフィールドが構造化されます:

import requests, json
from bs4 import BeautifulSoup

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
                  "(KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",
    "Accept-Language": "en-US,en;q=0.9",
}
proxies = {"http": "http://USER:PASS@gate.quantumproxies.io:8000",
           "https": "http://USER:PASS@gate.quantumproxies.io:8000"}

url = "https://www.walmart.com/ip/1756765288"
r = requests.get(url, headers=headers, proxies=proxies, timeout=20)

soup = BeautifulSoup(r.text, "html.parser")
blob = soup.find("script", id="__NEXT_DATA__")
data = json.loads(blob.string)
product = data["props"]["pageProps"]["initialData"]["data"]["product"]
print(product["name"], product["priceInfo"]["currentPrice"]["price"])

正確なキーのパスは時間とともに変わりますので、トップレベルのキーを一度印刷し、そこからナビゲートしてください。しかし、原則は変わりません: JSONは真実のソースであり、価格、在庫状況、販売者、バリアント、評価を一つの場所に含んでいます — フィールドごとのセレクターが壊れることはありません。

ドア: 「ロボットか人間か?」

データセンターIPからリクエストを実行すると、製品JSONは得られず、「ロボットか人間か?ボタンをアクティブにして保持し、人間であることを確認してください。」というページが表示されます。これがWalmartが実行するHUMAN(旧PerimeterX)というボット防御層です。IPの評判、TLSフィンガープリント、ヘッダーを一緒に評価し、スコアが低い場合に押して保持するチャレンジを提供します。

そのCAPTCHAを解決するのではなく、それを引き起こさないようにします。最大のレバーはIPです。住宅プロキシは実際のWalmartショッパーの接続として提示され、スコアを十分に高く保ち、実際のページを提供します。データセンターの範囲は疑わしいと事前にスコア付けされ、リクエスト1で壁にぶつかります。HUMANが自動化を検出する方法の内訳は、そのスコアに何が影響を与えるかをカバーしています。

Walmart製品データをスクレイピングするためのパイプライン: 製品URLを住宅出口を通して__NEXT_DATA__ JSONと構造化された行に
住宅出口を通してルートし、ハイドレーションJSONを読み取ります — パスに脆弱なHTMLセレクターはありません。

地理的価格: 一つの製品、多くの価格

Walmartの価格と在庫は店舗ごとに異なります。同じ商品でもショッピングの場所によって異なる価格と在庫状況が表示されるため、場所が設定されていないスクレイパーは任意の店舗を読み取っています。ZIPで場所を設定して、どの店舗の価格を取得するかを制御します — Walmartはそれを場所クッキーに保持するので、すべてのリクエストで送信してください:

# pin the store location by US ZIP before reading price/stock
cookies = {"assortmentStoreId": "3081", "locationData": '{"postalCode":"10001"}'}

r = requests.get(url, headers=headers, cookies=cookies,
                 proxies=proxies, timeout=20)
# now priceInfo + availabilityStatus reflect that store

市場間で製品を比較するには、ZIPリストをループし、それぞれをその地域の住宅出口とペアにします — ニューヨークのショッパーがNYC店舗の価格を読むのは、ある場所を主張しながら他の場所から出るリクエストよりもはるかに一貫性があります。その地理的な一貫性が競合価格監視の成否を決定します。

検索ページとページネーション

カタログ作業のためには、製品ページだけでなく検索結果をスクレイピングします。知っておくべきことは2つあります: Walmartはユーザーごとに検索順序をカスタマイズするため、実行ごとに安定したランクを期待しないでください。また、結果は複数のページにわたり、pageパラメータでページを移動します。同じ__NEXT_DATA__パターンが適用されます — 検索JSONは価格とIDを含むアイテムの完全なリストを持っているので、バリアントレベルの詳細を望まない限り、製品ページに触れる必要はほとんどありません:

def search(query, pages=5):
    items = []
    for page in range(1, pages + 1):
        url = f"https://www.walmart.com/search?q={query}&page={page}"
        html = requests.get(url, headers=headers, cookies=cookies,
                            proxies=proxies, timeout=20).text
        blob = BeautifulSoup(html, "html.parser").find("script", id="__NEXT_DATA__")
        data = json.loads(blob.string)
        stacks = data["props"]["pageProps"]["initialData"]["searchResult"]["itemStacks"]
        for stack in stacks:
            items += stack["items"]
    return items

手作業をやめるタイミング

生のリクエストと住宅IPでWalmartでかなりの距離を進むことができます。それが報われなくなるポイントはスケールです: リクエストごとに出口を回転させ、壁にぶつかるものを再試行し、数千のZIPにわたって店舗クッキーのロジックを一貫させることは実際のメンテナンス負担です。ブラウザのフィンガープリントを持ち、住宅IPを回転させ、解析されたJSONを返すことができるScraper APIはそれを単一の呼び出しにまとめます — Walmart URLを送信し、製品モデルを取得し、ブロックが処理されます。ページがデータの代わりにCAPTCHAシェルとして戻ってきた場合、それは古典的な空白ページの症状であり、それはレンダリングとIPの問題であり、パーサーのバグではありません。

Walmart HUMANの押して保持するCAPTCHAがデータセンターIPをブロックし、住宅IPがクリーンな製品JSONに通過する
押して保持するゲートを解決するのではなく、それが現れないように信頼スコアを十分に高く保ちます。

Walmartに到達する住宅IPを取得する

よくある質問

Walmartには製品データAPIがありますか?

任意の製品と価格データのための公開APIはありませんので、スクレイピングが一般的なルートです。WalmartのアフィリエイトおよびマーケットプレイスセラーAPIは存在しますが、制限されており、範囲が限られています。広範な製品、価格、在庫の収集のためには、住宅IPを通してページの__NEXT_DATA__ JSONを読むのが実用的な方法です。

Walmartの価格をブロックされずにスクレイピングする方法は?

リクエストを住宅プロキシ経由でルートし、HUMANのボット防御が本物のショッパーとしてスコアを付けるようにし、整合性のあるブラウザUser-AgentとAccept-Languageを送信し、ハイドレーションJSONを読み取ります。ZIPクッキーで店舗を固定し、出口地域をそれに一致させます。その組み合わせにより、ほとんどのリクエストで押して保持するCAPTCHAを回避できます。

なぜWalmartは同じ製品に異なる価格を表示するのですか?

Walmartの価格と在庫は店舗レベルです。セッションに設定された場所に応じて表示される価格が異なるため、異なるZIPの場所での2つのリクエストは正当に異なる価格を返します。比較可能なデータを収集するには、ZIPを明示的に固定し、プロキシ出口をその地域に一致させ、WalmartがIPから推測するのではなくします。

__NEXT_DATA__ JSONはHTMLを解析するよりも優れていますか?

はい、耐久性のために。Walmartの可視クラス名は頻繁に変更され、CSSセレクタースクレイパーを壊しますが、Next.jsのハイドレーションJSONは価格、バリアント、販売者、在庫を含む製品の安定した構造化モデルです。JSONを一度解析すれば、脆弱なフィールドごとのセレクターのスタックを回避できます。

Walmartはデータが隠されているから難しいのではありません — ページJSONにあります。難しいのは、誰がノックしているかを確認するドアです。タグの代わりに__NEXT_DATA__を読み、ZIPで店舗を設定し、住宅IPでノックすれば、スケールでクリーンで比較可能な製品データを取得できます。大規模な価格作業には、同じプレイブックがBest BuyやTargetにも拡張されます。

1つのAPIコールでWalmartをスクレイピングする