Comment scraper des boutiques Shopify avec des proxies : guide complet

Découvrez comment gratter Shopify données de stockage à l'aide JSON API paramètres et proxies résidentielles. Code complet Python et Node.js pour l'extraction des produits, des prix et des données d'inventaire.

Comment scraper des boutiques Shopify avec des proxies : guide complet

Pourquoi Scrape Shopify Stores?

Shopify pouvoirs plus de 4 millions de magasins en ligne dans le monde, des petites marques indépendantes aux grands détaillants. Cela en fait l'une des sources les plus riches de renseignements sur le commerce électronique. En grattant les magasins Shopify, vous pouvez suivre les prix des concurrents, surveiller les lancements de produits, analyser les tendances du marché et créer des bases de données complètes sur les produits.

La bonne nouvelle est que Shopify a une structure prévisible qui rend la démolition plus systématique que la plupart des plateformes de commerce électronique. Chaque magasin Shopify expose certaines données au moyen de paramètres normalisés, ce qui signifie qu'une seule architecture de racleur peut fonctionner dans des milliers de magasins différents. Pour un aperçu plus large des stratégies de démolition du commerce électronique, voir notre Guide de suppression des données sur le commerce électronique.

Comprendre la structure du magasin Shopify

Chaque magasin Shopify suit les mêmes modèles d'URL et de données, quel que soit le thème ou la personnalisation.

Points d'arrêt du JSON public

Shopify expose les données du produit à travers les paramètres JSON qui ne nécessitent pas d'authentification. Ce sont la façon la plus efficace de gratter les magasins Shopify parce que vous obtenez des données structurées sans analyse HTML.

Points d'arrêt du JSON public
Point d'arrivéeDonnées renvoyéesPagination
/products.jsonTous les produits avec variantes, prix, images?page=N&limit=250
/products/{handle}.jsonDétail du produit uniqueSans objet
/collections.jsonToutes les collections?page=N
/collections/{handle}/products.jsonProduits dans une collection?page=N&limit=250
/meta.jsonStockage des métadonnées (nom, description)Sans objet

Structure des données sur les produits

Chaque objet produit de l'API JSON comprend:

  • Informations de base: titre, poignée (slug), body html (description), fournisseur, type de produit, tags
  • Variantes: Chaque variante a son propre prix, compare at price, SKU, état des stocks et valeurs d'option (taille, couleur, etc.)
  • Images : URLs pour toutes les images de produits avec texte alt
  • Dates: created at, updated at, publied at

Limite des taux

Shopify applique des limites de taux pour protéger les performances des magasins. Les paramètres JSON publics permettent généralement 2-4 requêtes par seconde par IP avant de griffer. C'est là que Proxies résidentielles devenir essentiel — répartir les requêtes sur plusieurs IP vous permet de maintenir le débit sans frapper les limites de taux sur une seule IP.

Configuration mandataire pour Shopify

Shopify limite le taux en se basant sur l'IP, ce qui fait de la rotation par procuration la principale stratégie de graissage à l'échelle.

Configuration ProxyHat

# Rotating residential proxy (new IP per request)
http://USERNAME:PASSWORD@gate.proxyhat.com:8080
# Geo-targeted for region-specific stores
http://USERNAME-country-US:PASSWORD@gate.proxyhat.com:8080
# Sticky session for paginated scraping of one store
http://USERNAME-session-shopify001:PASSWORD@gate.proxyhat.com:8080

Pour Shopify gratter, utiliser la rotation par demande lors de la démolition de différents magasins, et des sessions collantes lors de la pagination à travers le catalogue de produits d'un seul magasin. Ce modèle imite le comportement de navigation naturel.

Mise en œuvre de Python

Voici un racleur Shopify prêt à la production Python SDK de ProxyHat.

Scrapeur d'API JSON

import requests
import json
import time
import random
from dataclasses import dataclass, field
from typing import Optional
PROXY_URL = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
]
@dataclass
class ShopifyProduct:
    id: int
    title: str
    handle: str
    vendor: str
    product_type: str
    tags: list[str]
    variants: list[dict]
    images: list[str]
    min_price: float
    max_price: float
    created_at: str
    updated_at: str
def get_session(store_domain: str) -> requests.Session:
    """Create a session with proxy and headers configured."""
    session = requests.Session()
    session.proxies = {"http": PROXY_URL, "https": PROXY_URL}
    session.headers.update({
        "User-Agent": random.choice(USER_AGENTS),
        "Accept": "application/json",
        "Accept-Language": "en-US,en;q=0.9",
    })
    return session
def scrape_all_products(store_domain: str) -> list[ShopifyProduct]:
    """Scrape all products from a Shopify store via JSON API."""
    products = []
    page = 1
    session = get_session(store_domain)
    while True:
        url = f"https://{store_domain}/products.json?page={page}&limit=250"
        try:
            response = session.get(url, timeout=30)
            response.raise_for_status()
        except requests.RequestException as e:
            print(f"Error on page {page}: {e}")
            break
        data = response.json()
        page_products = data.get("products", [])
        if not page_products:
            break
        for p in page_products:
            prices = [float(v["price"]) for v in p.get("variants", [])
                      if v.get("price")]
            product = ShopifyProduct(
                id=p["id"],
                title=p["title"],
                handle=p["handle"],
                vendor=p.get("vendor", ""),
                product_type=p.get("product_type", ""),
                tags=p.get("tags", "").split(", ") if p.get("tags") else [],
                variants=[{
                    "id": v["id"],
                    "title": v["title"],
                    "price": v["price"],
                    "compare_at_price": v.get("compare_at_price"),
                    "sku": v.get("sku"),
                    "available": v.get("available", False),
                } for v in p.get("variants", [])],
                images=[img["src"] for img in p.get("images", [])],
                min_price=min(prices) if prices else 0,
                max_price=max(prices) if prices else 0,
                created_at=p.get("created_at", ""),
                updated_at=p.get("updated_at", ""),
            )
            products.append(product)
        print(f"Page {page}: {len(page_products)} products (total: {len(products)})")
        page += 1
        time.sleep(random.uniform(1, 3))
    return products
def scrape_collections(store_domain: str) -> list[dict]:
    """Scrape all collections from a Shopify store."""
    collections = []
    page = 1
    session = get_session(store_domain)
    while True:
        url = f"https://{store_domain}/collections.json?page={page}"
        try:
            response = session.get(url, timeout=30)
            response.raise_for_status()
        except requests.RequestException:
            break
        data = response.json()
        page_collections = data.get("collections", [])
        if not page_collections:
            break
        collections.extend(page_collections)
        page += 1
        time.sleep(random.uniform(1, 2))
    return collections
# Example: Scrape multiple Shopify stores
if __name__ == "__main__":
    stores = [
        "example-store-1.myshopify.com",
        "example-store-2.com",
        "example-store-3.com",
    ]
    for store in stores:
        print(f"\nScraping: {store}")
        products = scrape_all_products(store)
        print(f"Found {len(products)} products")
        # Save to JSON
        with open(f"{store.replace('.', '_')}_products.json", "w") as f:
            json.dump([vars(p) for p in products], f, indent=2)
        time.sleep(random.uniform(3, 7))

Surveillance des variations de prix dans les magasins

def compare_prices(store_domain: str, previous_data: dict) -> list[dict]:
    """Compare current prices with previously stored data."""
    changes = []
    products = scrape_all_products(store_domain)
    for product in products:
        prev = previous_data.get(product.handle)
        if not prev:
            changes.append({
                "type": "new_product",
                "handle": product.handle,
                "title": product.title,
                "price": product.min_price,
            })
            continue
        if product.min_price != prev.get("min_price"):
            changes.append({
                "type": "price_change",
                "handle": product.handle,
                "title": product.title,
                "old_price": prev["min_price"],
                "new_price": product.min_price,
                "change_pct": ((product.min_price - prev["min_price"])
                               / prev["min_price"] * 100)
                              if prev["min_price"] else 0,
            })
    return changes

Mise en œuvre de Node.js

Une version Node.js utilisant Le nœud SDK de ProxyHat.

const axios = require("axios");
const { HttpsProxyAgent } = require("https-proxy-agent");
const fs = require("fs");
const PROXY_URL = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080";
const agent = new HttpsProxyAgent(PROXY_URL);
async function scrapeShopifyProducts(storeDomain) {
  const products = [];
  let page = 1;
  while (true) {
    const url = `https://${storeDomain}/products.json?page=${page}&limit=250`;
    try {
      const { data } = await axios.get(url, {
        httpsAgent: agent,
        headers: {
          "User-Agent":
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
          Accept: "application/json",
        },
        timeout: 30000,
      });
      const pageProducts = data.products || [];
      if (pageProducts.length === 0) break;
      for (const p of pageProducts) {
        const prices = p.variants.map((v) => parseFloat(v.price)).filter(Boolean);
        products.push({
          id: p.id,
          title: p.title,
          handle: p.handle,
          vendor: p.vendor,
          productType: p.product_type,
          tags: p.tags ? p.tags.split(", ") : [],
          minPrice: Math.min(...prices),
          maxPrice: Math.max(...prices),
          variants: p.variants.map((v) => ({
            id: v.id,
            title: v.title,
            price: v.price,
            compareAtPrice: v.compare_at_price,
            sku: v.sku,
            available: v.available,
          })),
          images: p.images.map((img) => img.src),
          updatedAt: p.updated_at,
        });
      }
      console.log(`Page ${page}: ${pageProducts.length} products (total: ${products.length})`);
      page++;
      // Random delay 1-3 seconds
      await new Promise((r) => setTimeout(r, 1000 + Math.random() * 2000));
    } catch (err) {
      console.error(`Error on page ${page}: ${err.message}`);
      break;
    }
  }
  return products;
}
async function scrapeMultipleStores(stores) {
  const results = {};
  for (const store of stores) {
    console.log(`\nScraping: ${store}`);
    const products = await scrapeShopifyProducts(store);
    results[store] = products;
    console.log(`Found ${products.length} products`);
    // Delay between stores
    await new Promise((r) => setTimeout(r, 3000 + Math.random() * 4000));
  }
  return results;
}
// Usage
scrapeMultipleStores([
  "example-store-1.myshopify.com",
  "example-store-2.com",
]).then((results) => {
  fs.writeFileSync("shopify_data.json", JSON.stringify(results, null, 2));
  console.log("Data saved to shopify_data.json");
});

Stratégies de scrapage spécifiques

Découvrez les magasins Shopify

Avant de gratter, vous devez identifier quels sites concurrents fonctionnent sur Shopify. Les indicateurs communs sont les suivants:

  • Les /products.json le paramètre retourne JSON valide
  • Source HTML contient Shopify.theme ou cdn.shopify.com
  • Les x-shopify-stage en-tête est présent dans les réponses

Gestion des magasins Passworded

Certains magasins Shopify nécessitent un mot de passe pour y accéder. Ce sont généralement des magasins de pré-lancement ou de gros. Les paramètres JSON retourneront une redirection vers la page de mot de passe. Passez ces magasins dans votre pipeline à moins d'avoir un accès autorisé.

Traitement des domaines personnalisés

Shopify magasins utilisent souvent des domaines personnalisés au lieu de .myshopify.com. L'API JSON fonctionne de la même manière sur des domaines personnalisés. Utilisez simplement le domaine public du magasin dans vos demandes.

Suivi des inventaires

Les variantes de produits comprennent available champ indiquant l'état du stock. En suivant ce champ au fil du temps, vous pouvez surveiller les niveaux d'inventaire des concurrents et identifier quand les produits sortent des stocks — renseignements utiles pour les décisions de tarification et de restockage.

Éviter les blocs et les limites de taux

Alors que Shopify est plus facile à gratter qu'Amazon, il applique toujours les protections.

Éviter les blocs et les limites de taux
ProtectionDétailsAtténuation
Limite du taux de PI~2-4 req/sec par IP pour les paramètres JSONRotation des procurations résidentielles à travers les demandes
Protection contre les nuagesCertains magasins utilisent CloudflareIP résidentielles avec en-têtes de type navigateur
Détection du botPatterns comportementaux suivisRandomiser les retards et les agents utilisateurs
Pages de mot de passeMagasins de pré-lancement et de gros verrouillésSauter ou utiliser l'accès autorisé

Pour en savoir plus sur la manipulation des systèmes anti-bots, lisez notre guide sur comment gratter des sites Web sans se faire bloquer.

Key takeaway: L'API JSON de Shopify est l'approche de grattage la plus efficace — elle vous donne des données structurées sans analyse HTML. Utilisez-le avant de revenir à la grattage HTML.

Cas d'utilisation des données

Une fois que vous avez recueilli les données Shopify produit, voici les applications les plus précieuses:

  • Prix concurrentiels: Suivez les prix des concurrents selon les catégories de produits et ajustez votre stratégie de tarification en temps réel.
  • Recherche sur les produits : Identifier les produits de tendance, les nouveaux lancements et les lacunes du marché en surveillant plusieurs magasins.
  • Analyse du marché: Données agrégées sur des centaines de magasins Shopify pour comprendre les tendances du marché, la distribution des prix et la croissance des catégories.
  • enrichissement du catalogue: Utilisez des descriptions de produits concurrents, des images et des spécifications pour améliorer vos propres listes.
  • Surveillance de la marque: Suivez les vendeurs non autorisés de vos produits et surveillez la conformité MAP dans les magasins Shopify.

A emporter des clés

  • Boutiques /products.json endpoint est la méthode de grattage la plus efficace — utilisez-la avant l'analyse HTML.
  • Une architecture de racleur unique fonctionne dans tous les magasins Shopify en raison de la structure normalisée.
  • Les proxys résidentiels avec rotation ont surmonté la limite de taux IP de Shopify.
  • Utilisez des sessions collantes lors de la pagination à travers le catalogue d'un seul magasin.
  • Suivre les prix et la disponibilité des variantes pour une intelligence concurrentielle complète.
  • Commencez par Proxies résidentielles de ProxyHat à l'échelle de votre Shopify grattage fiable.

Prêt à commencer à gratter Shopify magasins? Explorez notre Guide de suppression des données sur le commerce électronique pour la stratégie complète, et vérifier notre Guide de proxy Python et Guide de proxy Node.js pour les détails de mise en œuvre. Visitez notre page de prix pour commencer.

Prêt à commencer ?

Accédez à plus de 50M d'IPs résidentielles dans plus de 148 pays avec filtrage IA.

Voir les tarifsProxies résidentiels
← Retour au Blog