كيفية استخراج متاجر Shopify باستخدام البروكسيات: دليل شامل

تعلّم كيفية تخريد بيانات المخزن باستخدام النقاط النهائية للشركة ووكالة الإقامة. Compython and Node.js code for extracting products, prices, and inventory data.

كيفية استخراج متاجر Shopify باستخدام البروكسيات: دليل شامل

لمَ تُحلق (سراب ستور)؟

تُحدّدُ القوىَ أكثر من 4 ملايين مخزن على الإنترنت في جميع أنحاء العالم، مِنْ العلامات التجارية المستقلة الصغيرة إلى المتاجر الكبرى. هذا يجعلها واحدة من أغنى مصادر معلومات التجارة الإلكترونية عن طريق تخريد المخازن، يمكنك تتبع تسعير المنافسين، ورصد عمليات إطلاق المنتجات، وتحليل اتجاهات السوق، وبناء قواعد بيانات شاملة للمنتجات.

والخبر السار هو أن الحلف له هيكل يمكن التنبؤ به يجعل الخردة أكثر انتظاما من معظم منابر التجارة الإلكترونية. ويكشف كل متجر عن بعض البيانات من خلال نقاط نهاية موحدة، مما يعني أن هيكل الخردة الواحد يمكن أن يعمل عبر آلاف من المتاجر المختلفة. وللاطلاع على نظرة عامة أوسع لاستراتيجيات تكسير التجارة الإلكترونية، انظر دليل جرد بيانات التجارة الإلكترونية.

فهم هيكل المخزن

ويتبع كل مخزن يُحلّل نفس أنماط URL والبيانات، بغض النظر عن الموضوع أو التكييف.

Public JSON Endpoints

Shopify exposes product data through JSON endpoints that do not require authentication. هذه هي الطريقة الأكثر كفاءة لتخريد المتاجر لأنك تحصل على بيانات منظمة بدون حزم HTML.

Public JSON Endpoints
نقطة النهايةالبيانات المعادةالهجرات
/products.jsonجميع المنتجات ذات المتغيرات والأسعار والصور?page=N&limit=250
/products/{handle}.jsonتفاصيل المنتجات الوحيدةN/A
/collections.jsonجميع المجموعات?page=N
/collections/{handle}/products.jsonالمنتجات في مجموعة?page=N&limit=250
/meta.jsonالبيانات الوصفية المسروقة (الاسم، الوصف)N/A

هيكل بيانات المنتجات

ويشتمل كل منتج من المنتجين التابعين للرابطة على ما يلي:

  • المعلومات الأساسية: اللقب، المقبض (الزئبق)، الجسم: html (الوصف)، البائع، المنتج - النوع، البطاقات
  • Variants: ولكل متغير سعره الخاص، ويقارن - في - السعر، والوحدة الخاصة، وحالة المخزون، وقيم الخيار (الحجم، واللون، وما إلى ذلك)
  • الصور: URLs for all product images with alt text
  • التاريخ: نُشِرَت في دقّة مُحدّثة، نُشرت

الحد الأدنى

تُحدّد الحدود القصوى للمعدلات اللازمة لحماية أداء المخزن. The public JSON endpoints typically allow 2-4 requests per second per IP before throtling kicks in. هذا هو المكان مؤسسات الرعاية يصبح أمراً أساسياً - نشر الطلبات عبر شركاء التنفيذ المتعددين يجعلك تحافظين على المخرج دون الحد من معدل ضرب أي شخص من شركاء التنفيذ.

Proxy Configuration for Shopify

الحد من معدل التخزين هو على الإنترنت، جعل التناوب المحترف الاستراتيجية الأولية للخردة على نطاق واسع.

ProxyHat Setup

# 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

لتخزين الخردة، استخدام التناوب لكل طلب عندما تخريد متاجر مختلفة، وجلسات ملصقة عندما تمهيد من خلال كتالوج منتجات متجر واحد. هذا النمطِ يُقلّمُ السلوكِ الطبيعيِ.

Python Implementation

هنا مُخدّرات مُخدّرة مُخدّرة للإنتاج باستخدام مُخدّرات (بروكسي هات) (بايتون).

JSON API Scraper

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))

Monitoring Price Changes Across Stores

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

Node.js Implementation

نسخة من Node.js باستخدام العميل (س.د.ك).

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");
});

Shopify-Specific Scraping Strategies

Discovering Shopify Stores

قبل الخردة، تحتاج إلى تحديد أي مواقع منافسة تجري على التصفيق. وتشمل المؤشرات المشتركة ما يلي:

  • The /products.json عودة نقطة النهاية سارية
  • HTML source contains Shopify.theme أو cdn.shopify.com
  • The x-shopify-stage العنوان موجود في الردود

Handling Passworded Stores

بعض المتاجر المتحركة تتطلب كلمة سر للدخول وعادة ما تكون هذه مخازن قبل الإطلاق أو بالجملة. The JSON endpoints will return a redirect to the password page. تزلج هذه المتاجر في خط الخردة الخاص بك إلا إذا كان لديك تصريح الدخول.

التعامل مع (كوست دومين)

وكثيراً ما تستخدم المخازن النطاقات الجمركية بدلاً من ذلك .myshopify.comThe JSON API works the same way on custom domains. فقط إستخدمي نطاق المخزن العام في طلباتك

تعقب المخزون

تشمل متغيرات المنتجات available الحقل الذي يشير إلى حالة المخزون. ومن خلال تتبع هذا المجال على مر الزمن، يمكن أن ترصد مستويات المخزون المنافس، وأن تحدد متى تخرج المنتجات من المخزون - الذكاء المفيد لقرارات التسعير وإعادة التخزين.

تجنب الحواجز والحدود المرتفعة

وفي حين أن التهريب هو أكثر مواتاة للخردة من الأمازون، فإنه لا يزال يفرض الحماية.

تجنب الحواجز والحدود المرتفعة
الحمايةالتفاصيلالتخفيف
الحد الأدنى02-4 req/sec per IP for JSON endpointsتناوب العملاء المقيمين عبر الطلبات
حماية السحاببعض المتاجر تستخدم كلودفليرIPs in Residential IPs with browser-like headers
Bot Detectionرصد الأنماط السلوكيةحالات التأخير والامتيازات
كلمات السرمخازن ما قبل الإطلاق/البيعالوصول المأذون به

من أجل المزيد عن التعامل مع أنظمة مضادة للمركبات، قراءة دليلنا على كيف تخريد المواقع دون أن تغلق.

"الطريق الرئيسي: "تحلّق (جون بي آي) هو أكفأ نهج للخردة إستخدمه قبل أن يتراجع إلى (ه.ت.ل)

حالات استخدام البيانات

بمجرد أن تُجمع بيانات المنتج، ها هي التطبيقات الأكثر قيمة:

  • التسعير التنافسي: تعقّب أسعار المنافسين عبر فئات المنتجات وتعديل استراتيجيتك للتسعير في الوقت الحقيقي
  • بحوث المنتجات: تحديد المنتجات المتجهة، وعمليات الإطلاق الجديدة، والثغرات السوقية عن طريق رصد المتاجر المتعددة.
  • تحليل السوق: تجميع البيانات عبر مئات المخازن لفهم اتجاهات السوق، وتوزيع الأسعار، ونمو الفئات.
  • الإثراء المكتال: استخدمي وصف المنتجات المنافسة والصور والمواصفات لتحسين قوائمك
  • رصد براند: تعقب بائعين غير مرخصين لمنتجاتك وترصد امتثال شركة (إم بي) عبر واجهات التخزين

المداخل الرئيسية

  • التسوق /products.json إن نقطة النهاية هي أنجع طريقة للخردة - تستخدمها قبل أن تقطع شركة HTML.
  • مصمم واحد للخردة يعمل في جميع المخازن بسبب الهيكل الموحد
  • المحترفون المقيمون مع التناوب تغلبوا على معدل الـ "إب بي" المُحدّد
  • إستخدمي جلسات ملصقة عندما تمهّد في كتالوج متجر واحد
  • Track variant-level pricing and availability for comprehensive competitive intelligence.
  • ابدأ وكيلات النيابة السكنية لتمشيط الخردة بشكل موثوق

مستعد للبدء بتخريد المتاجر؟ نستكشف دليل جرد بيانات التجارة الإلكترونية من أجل الإستراتيجية الكاملة Python proxy و Node.js proxy guide لتفاصيل التنفيذ. زيارة لنا الصفحة للبدء

¿Listo para empezar?

Accede a más de 50M de IPs residenciales en más de 148 países con filtrado impulsado por IA.

Ver preciosProxies residenciales
← Volver al Blog