אוטומציה של ניטור מחירים במרקטפלייסים: מ-API ועד Playwright

ניטור מחירים ידני בשווקים מקוונים גוזל זמן ומוביל לאובדן הכנסות בשל נתונים מיושנים. אנו בונים פתרונות אוטומטיים לאיסוף וניתוח מחירים הפועלים באמינות גם תחת הגנה מורכבת. הצוות שלנו מספק את הפרויקט במפתח מלא—מביקורת ובחירת אסטרטגיה ועד יישום ותמיכה שוטפת.

פיתוח ותחזוקה של כל סוגי האתרים:

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי B2B, שווקים, בורסות מקוונות, אתרי קאשבק, בורסות, פלטפורמות דרופשיפינג, מנתחי מוצרים
יישומי אינטרנט לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, פורטלים ארגוניים, מערכות ניהול ייצור, מנתחי מידע
אתרי שירות אלקטרוני או יישומי אינטרנט
פלטפורמות מודעות, בתי ספר מקוונים, בתי קולנוע מקוונים, בוני אתרים, פורטלים לשירותים אלקטרוניים, פלטפורמות אירוח וידאו, פורטלים נושאיים

אלה רק חלק מהסוגים הטכניים של אתרים שאנו עובדים איתם, ולכל אחד מהם יכולים להיות מאפיינים ופונקציונליות ספציפיים משלו, וכן ניתן להתאים אותם לצרכים ולמטרות הספציפיים של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
אוטומציה של ניטור מחירים במרקטפלייסים: מ-API ועד Playwright
מורכב
~5 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1365
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113
  • פיתוח אתר עבור SBH Partners
    פיתוח אתר עבור SBH Partners
    1201
  • פיתוח אתר עבור Red Pear
    פיתוח אתר עבור Red Pear
    619

כשניטור ידני מנקז את התקציב שלך

החנות שלך ב-Wildberries מפסידה עד 30% מההכנסות בגלל מחירי מתחרים מיושנים? בדיקה ידנית של 15,000 פריטים היא 5 ימי עבודה בשבוע, וטעות בתמחור יכולה לעלות בערך $9–13 בחיסכון. אנחנו, צוות עם 5 שנות ניסיון ו-40+ פרויקטי גירוד מוצלחים, יודעים כיצד להפוך תהליך זה לאוטומטי ללא סיכון של חסימה. אנו מציעים פתרון סוהר מניתוח ועד אינטגרציה עם ה-CRM שלך.

במאמר זה נסקור שלוש אסטרטגיות לאיסוף נתונים עבור מרקטפלייסים: שימוש ב-API רשמיים, גירוד נקודות קצה ציבוריות של JSON, ואוטומציה של דפדפן עם עקיפת Cloudflare. תקבלו קטעי קוד מוכנים עבור Wildberries, Ozon ו-Amazon, וכן רשימת בדיקה למניעת זיהוי כדי להבטיח פעולה יציבה.

API רשמיים לעומת גירוד: מה לבחור

לפני כתיבת סקריפט גירוד, בדקו את היכולות הרשמיות. API מספקים נתונים מובנים אך מוגבלים למוצרים שלכם. לצורך ניתוח תחרותי, תצטרכו לגרד.

מרקטפלייס API רשמי מגבלות
Ozon Seller API (למוכרים) רק המוצרים שלכם
Wildberries Seller API, Statistics API רק הנתונים שלכם
Amazon Product Advertising API דורש שותפות
Yandex.Market Partner API לשותפים

גירוד מוצרים של מוכרים אחרים הוא אזור אפור בתנאי השירות. אנו משתמשים בזה אך ורק לניתוח תחרותי, ניטור מחירים ומחקר שוק. API חוקיים הם קו הבסיס; גירוד מרחיב אותם.

איך לעקוף את הגנת Cloudflare ב-Ozon?

Ozon בונה דפים עם React; נתונים מועברים דרך בקשות XHR. Cloudflare בודק את סביבת ה-JavaScript, כך ש-requests פשוט לא יעבוד. הפתרון שלנו: Playwright עם אמולציית דפדפן אמיתית, יירוט תגובות API וסיבוב User-Agent. הנה דוגמה לסקריפט גירוד:

# scraper/ozon.py
from playwright.async_api import async_playwright
import json

class OzonScraper:
    async def scrape_product(self, url: str) -> dict:
        async with async_playwright() as p:
            browser = await p.chromium.launch(headless=True)
            context = await browser.new_context(
                user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
                viewport={"width": 1366, "height": 768},
            )
            # Перехватываем API-ответы с данными товара
            product_data = {}
            async def handle_response(response):
                if "/api/entrypoint-api.bx/page/json" in response.url:
                    try:
                        data = await response.json()
                        widget_states = data.get("widgetStates", {})
                        for key, value in widget_states.items():
                            if "webProductHeading" in key:
                                product_data["heading"] = json.loads(value)
                            elif "webPrice" in key:
                                product_data["price"] = json.loads(value)
                    except Exception:
                        pass
            context.on("response", handle_response)
            page = await context.new_page()
            await page.goto(url, wait_until="networkidle")
            await browser.close()
            return self._normalize_ozon(product_data)

    def _normalize_ozon(self, data: dict) -> dict:
        heading = data.get("heading", {})
        price = data.get("price", {})
        return {
            "name": heading.get("title"),
            "sku": heading.get("sku"),
            "price": self._parse_price(price.get("price", "")),
            "original_price": self._parse_price(price.get("originalPrice", "")),
            "discount": price.get("discount"),
        }

    def _parse_price(self, s: str) -> float:
        return float("".join(c for c in s if c.isdigit() or c == ".") or 0)

Playwright יציב פי 3 מ-Selenium באתרים דינמיים בזכות המתנה מובנית ותמיכה בדפדפנים מודרניים. להגנה נוספת, אנו משתמשים ב-# scraper/ozon.py from playwright.async_api import async_playwright import json class OzonScraper: async def scrape_product(self, url: str) -> dict: async with async_playwright() as p: browser = await p.chromium.launch(headless=True) context = await browser.new_context( user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64)", viewport={"width": 1366, "height": 768}, ) # Перехватываем API-ответы с данными товара product_data = {} async def handle_response(response): if "/api/entrypoint-api.bx/page/json" in response.url: try: data = await response.json() widget_states = data.get("widgetStates", {}) for key, value in widget_states.items(): if "webProductHeading" in key: product_data["heading"] = json.loads(value) elif "webPrice" in key: product_data["price"] = json.loads(value) except Exception: pass context.on("response", handle_response) page = await context.new_page() await page.goto(url, wait_until="networkidle") await browser.close() return self._normalize_ozon(product_data) def _normalize_ozon(self, data: dict) -> dict: heading = data.get("heading", {}) price = data.get("price", {}) return { "name": heading.get("title"), "sku": heading.get("sku"), "price": self._parse_price(price.get("price", "")), "original_price": self._parse_price(price.get("originalPrice", "")), "discount": price.get("discount"), } def _parse_price(self, s: str) -> float: return float("".join(c for c in s if c.isdigit() or c == ".") or 0) — תוסף שמסתיר אוטומציה.

למה קל יותר לגרד את Wildberries?

ל-Wildberries יש API ציבוריים של JSON שאינם דורשים אימות. הם עובדים ישירות, ללא JavaScript, מה שמפשט את איסוף הנתונים. דוגמה לסקריפט באמצעות playwright-stealth ו-httpx:

# scraper/wildberries.py
import httpx
import asyncio
from typing import Optional

class WildberriesScraper:
    CARD_URL = "https://card.wb.ru/cards/v2/detail"
    SEARCH_URL = "https://search.wb.ru/exactmatch/ru/common/v9/search"
    CATALOG_URL = "https://catalog.wb.ru/catalog/{shard}/v2/catalog"

    def __init__(self):
        self.client = httpx.AsyncClient(
            headers={
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
                "Accept": "*/*",
                "Origin": "https://www.wildberries.ru",
                "Referer": "https://www.wildberries.ru/",
            },
            timeout=15,
        )

    async def get_product(self, nm_id: int) -> Optional[dict]:
        """Получение карточки товара по артикулу WB"""
        params = {
            "appType": 1,
            "curr": "rub",
            "dest": -1257786,  # Москва
            "nm": nm_id,
        }
        resp = await self.client.get(self.CARD_URL, params=params)
        resp.raise_for_status()
        data = resp.json()
        products = data.get("data", {}).get("products", [])
        if not products:
            return None
        return self._normalize_product(products[0])

    def _normalize_product(self, raw: dict) -> dict:
        sizes = raw.get("sizes", [])
        price_data = sizes[0].get("price", {}) if sizes else {}
        return {
            "nm_id": raw["id"],
            "name": raw.get("name"),
            "brand": raw.get("brand"),
            "supplier_id": raw.get("supplierId"),
            "rating": raw.get("reviewRating"),
            "feedbacks": raw.get("feedbacks"),
            "price": price_data.get("product", 0) / 100,
            "sale_price": price_data.get("total", 0) / 100,
            "discount": raw.get("sale", 0),
            "colors": [c["name"] for c in raw.get("colors", [])],
        }

    async def search_products(self, query: str, page: int = 1) -> list[dict]:
        params = {
            "appType": 1,
            "curr": "rub",
            "dest": -1257786,
            "page": page,
            "query": query,
            "resultset": "catalog",
            "sort": "popular",
        }
        resp = await self.client.get(self.SEARCH_URL, params=params)
        resp.raise_for_status()
        products = resp.json().get("data", {}).get("products", [])
        return [self._normalize_product(p) for p in products]

    async def scrape_category(self, shard: str, query: str, pages: int = 5) -> list[dict]:
        """Обход категории постранично"""
        all_products = []
        for page in range(1, pages + 1):
            products = await self.search_products(query, page)
            if not products:
                break
            all_products.extend(products)
            await asyncio.sleep(1.5)  # Пауза между запросами
        return all_products

שימו לב ל-asyncio — הפסקה חובה בין בקשות כדי למנוע הגבלת קצב. לאיסוף בקנה מידה גדול, אנו מוסיפים סיבוב פרוקסי דרך Bright Data או IPRoyal.

Amazon: API רשמי אמין יותר

עבור Amazon, אנו ממליצים על Product Advertising API 5.0. הוא מספק גישה למחירים, דירוגים ותיאורים. גירוד דפדפן כאן פחות יעיל בגלל הגנה אגרסיבית. דוגמה:

# scraper/amazon_pa.py
from paapi5_python_sdk import DefaultApi, SearchItemsRequest, PartnerType

class AmazonScraper:
    def __init__(self, access_key: str, secret_key: str, partner_tag: str):
        self.api = DefaultApi(
            access_key=access_key,
            secret_key=secret_key,
            host="webservices.amazon.com",
            region="us-east-1",
        )
        self.partner_tag = partner_tag

    def search_products(self, keywords: str, category: str = "All") -> list[dict]:
        request = SearchItemsRequest(
            partner_tag=self.partner_tag,
            partner_type=PartnerType.ASSOCIATES,
            keywords=keywords,
            search_index=category,
            item_count=10,
            resources=[
                "ItemInfo.Title",
                "Offers.Listings.Price",
                "Images.Primary.Large",
                "ItemInfo.Features",
            ],
        )
        response = self.api.search_items(request)
        return [self._normalize(item) for item in response.search_result.items]

    def _normalize(self, item) -> dict:
        price = None
        if item.offers and item.offers.listings:
            price = item.offers.listings[0].price.amount
        return {
            "asin": item.asin,
            "title": item.item_info.title.display_value if item.item_info else None,
            "price": price,
            "image": item.images.primary.large.url if item.images else None,
            "url": item.detail_page_url,
        }

ה-API דורש חשבון שותף, אבל הנתונים חוקיים ומובנים. לנפחים קטנים, זו האפשרות הטובה ביותר.

תזמור סקריפטים ב-Laravel

יש לאחסן ולעדכן את הנתונים שנאספו. בפרויקטים שלנו, אנו משתמשים ב-Laravel עם תורים וסקריפטים של Python המופעלים דרך Process:

// app/Console/Commands/ScrapeMarketplace.php
class ScrapeMarketplace extends Command
{
    protected $signature = 'scrape:marketplace {marketplace} {--query=} {--pages=5}';

    public function handle(): void
    {
        $marketplace = $this->argument('marketplace');
        $query = $this->option('query');
        $pages = (int) $this->option('pages');

        $process = new Process([
            'python3',
            base_path('scraper/run.py'),
            '--marketplace',
            $marketplace,
            '--query',
            $query,
            '--pages',
            $pages,
            '--output',
            storage_path("scraper/{$marketplace}_output.json"),
        ]);

        $process->setTimeout(300)->run();

        if ($process->isSuccessful()) {
            $data = json_decode(file_get_contents(
                storage_path("scraper/{$marketplace}_output.json")
            ), true);

            foreach ($data as $item) {
                MarketplaceProduct::updateOrCreate(
                    ['marketplace' => $marketplace, 'external_id' => $item['nm_id'] ?? $item['asin']],
                    $item + ['scraped_at' => now()]
                );
            }

            $this->info("Импортировано: " . count($data) . " товаров");
        } else {
            Log::error($process->getErrorOutput());
        }
    }
}

ארכיטקטורה זו מקלה על קנה מידה: הוסיפו מרקטפלייס חדש, כתבו סקריפט נפרד, והריצו את אותה פקודה.

אמצעי מניעת זיהוי: רשימת בדיקה

איום פתרון
חסימת IP פרוקסי מתחלף (Bright Data, IPRoyal)
טביעת אצבע של User-Agent אקראיות + עדכון
טביעת אצבע של דפדפן תוסף stealth של Playwright
הגבלת קצב הפסקות אקראיות 1-5 שניות
CAPTCHA 2captcha / anti-captcha API
קישורי Honeypot סינון קישורים בלתי נראים

אנו מבטיחים שהתצורה שלנו עוברת 99% מבדיקות Cloudflare.

מה כלול בפיתוח סקריפט גירוד סוהר

  1. ניתוח המרקטפלייס היעד ובחירת האסטרטגיה האופטימלית (API, גירוד, דפדפן)
  2. כתיבת הסקריפט ב-Python עם asyncio או Playwright
  3. הגדרת סיבוב פרוקסי ו-User-Agent
  4. נורמליזציה של נתונים: תקנון מחירים, הסרת כפילויות, ניקוי HTML
  5. אינטגרציה עם ה-CRM, ERP או Google Sheets שלכם דרך REST API או CSV
  6. תיעוד והדרכת צוות
  7. תמיכה ל-3 חודשים — תיקון תקלות כשהאתר משתנה

לוח זמנים לפיתוח

מרקטפלייס מורכבות לוח זמנים
Wildberries (JSON API) בינוני 3-5 ימים
Ozon (Playwright) גבוה 5-8 ימים
Amazon (PA API) נמוך 2-3 ימים
Yandex.Market בינוני 3-5 ימים
+ ניטור והתראות +2-3 ימים

נעריך את הפרויקט שלכם. צרו קשר לייעוץ — נבחר את הארכיטקטורה ולוח הזמנים האופטימליים. הזמינו פיתוח סקריפט גירוד סוהר כבר עכשיו.

תיעוד Playwright