لمَ تُحلق (سراب ستور)؟
تُحدّدُ القوىَ أكثر من 4 ملايين مخزن على الإنترنت في جميع أنحاء العالم، مِنْ العلامات التجارية المستقلة الصغيرة إلى المتاجر الكبرى. هذا يجعلها واحدة من أغنى مصادر معلومات التجارة الإلكترونية عن طريق تخريد المخازن، يمكنك تتبع تسعير المنافسين، ورصد عمليات إطلاق المنتجات، وتحليل اتجاهات السوق، وبناء قواعد بيانات شاملة للمنتجات.
والخبر السار هو أن الحلف له هيكل يمكن التنبؤ به يجعل الخردة أكثر انتظاما من معظم منابر التجارة الإلكترونية. ويكشف كل متجر عن بعض البيانات من خلال نقاط نهاية موحدة، مما يعني أن هيكل الخردة الواحد يمكن أن يعمل عبر آلاف من المتاجر المختلفة. وللاطلاع على نظرة عامة أوسع لاستراتيجيات تكسير التجارة الإلكترونية، انظر دليل جرد بيانات التجارة الإلكترونية.
فهم هيكل المخزن
ويتبع كل مخزن يُحلّل نفس أنماط URL والبيانات، بغض النظر عن الموضوع أو التكييف.
Public JSON Endpoints
Shopify exposes product data through JSON endpoints that do not require authentication. هذه هي الطريقة الأكثر كفاءة لتخريد المتاجر لأنك تحصل على بيانات منظمة بدون حزم HTML.
| نقطة النهاية | البيانات المعادة | الهجرات |
|---|---|---|
/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 changesNode.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 لتفاصيل التنفيذ. زيارة لنا الصفحة للبدء






