פיתוח בוט לניתוח מחירי מתחרים לפי לוח זמנים

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

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

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

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

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
פיתוח בוט לניתוח מחירי מתחרים לפי לוח זמנים
בינוני
~3-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

בוט ניטור מחירים: ניתוח אוטומטי של מחירי מתחרים לפי לוח זמנים

תארו לעצמכם: המתחרה שלכם מוריד מחירים ב-15% על 20 המוצרים המובילים שלו, ואתם מגלים זאת רק כעבור שבוע, כשהמכירות כבר צנחו. זה בדיוק מה שקרה לאחד הלקוחות שלנו, שאיבד 30% מהמרווח שלו בחודש אחד. כדי למנוע תרחישים כאלה, אנו בונים בוטים אוטומטיים לניתוח מחירים שפועלים לפי לוח זמנים, שומרים היסטוריה, ויכולים להתאים את המחירים שלכם באופן עצמאי לפי חוקים גמישים. עם ניסיון של 7+ שנים ו-40+ פרויקטים של מסחר אלקטרוני שהושלמו, אנו מבטיחים פעולה אמינה של הניתוח בכל שלב. צרו קשר לקבלת בוט ניטור מחירים מותאם לקטלוג שלכם.

למה ניטור מחירים ידני אינו יעיל

  • נתונים מיושנים: אתם בודקים מחירים פעם בשבוע, בעוד המתחרים משנים אותם מדי יום. עד שתגיבו, כבר הפסדתם מכירות או מרווח.
  • אמצעי אנטי-בוט: מתחרים משתמשים ב-Cloudflare, קפטצ'ות, וסלקטורים דינמיים. איסוף ידני לא מספיק—אתם צריכים דפדפן ללא ראש עם רוטציית פרוקסי.
  • נורמליזציה: מחירים מגיעים בפורמטים שונים: עם/בלי מס, מטבעות שונים, רווחים, סמלים. ללא נורמליזציה, השוואות חסרות משמעות.

איך אנו בונים את מערכת הניטור

אנו משתמשים ב-Laravel 11 על PHP 8.3, PostgreSQL לאחסון, Redis לתורים, ו-Playwright לניתוח תוכן דינמי. הארכיטקטורה מבוססת מיקרוסרביסים—כל מתחרה מעובד באופן עצמאי.

Scheduler → ScrapeCompetitorPrices Job (per competitor) → CompetitorScraper (HTTP/Playwright) → PriceNormalizer → PriceHistoryRepository (INSERT) → PriceChangeDetector → AlertDispatcher (если изменение > порога) → RepricingEngine (если включён autoprice) 

מודל נתונים

// database/migrations/create_competitor_prices_table.php
Schema::create('competitor_prices', function (Blueprint $table) {
    $table->id();
    $table->foreignId('product_id')->constrained();
    $table->foreignId('competitor_id')->constrained();
    $table->string('competitor_sku')->nullable();
    $table->string('competitor_url');
    $table->decimal('price', 12, 2);
    $table->decimal('sale_price', 12, 2)->nullable();
    $table->boolean('in_stock')->default(true);
    $table->timestamp('scraped_at');
    $table->timestamps();
    $table->index(['product_id', 'competitor_id', 'scraped_at']);
});

// История для графиков и аналитики
Schema::create('competitor_price_history', function (Blueprint $table) {
    $table->id();
    $table->foreignId('product_id')->constrained();
    $table->foreignId('competitor_id')->constrained();
    $table->decimal('price', 12, 2);
    $table->boolean('in_stock');
    $table->date('recorded_date');
    $table->timestamps();
    $table->unique(['product_id', 'competitor_id', 'recorded_date']);
});

תצורת מתחרה

// config/competitors.php
return [
    'competitor_a' => [
        'name' => 'Shop A',
        'base_url' => 'https://shop-a.ru',
        'selectors' => [
            'price' => '.current-price',
            'in_stock' => '.in-stock-badge',
        ],
        'price_regex' => '/[\d\s]+/',
        'url_pattern' => 'https://shop-a.ru/product/{sku}',
        'requires_js' => false,
        'request_delay' => [1000, 3000], // ms
    ],
    'wildberries' => [
        'name' => 'Wildberries',
        'type' => 'api',
        'scraper' => WildberriesPriceScraper::class,
        'request_delay' => [500, 1500],
    ],
];

מחלץ מחירים בסיסי

// app/Services/PriceMonitor/CompetitorPriceScraper.php
class CompetitorPriceScraper
{
    public function __construct(
        private Client $httpClient,
        private array $config
    ) {}

    public function scrapePrice(string $url): ?PriceData
    {
        try {
            $html = $this->fetch($url);
            $crawler = new Crawler($html);

            $priceText = $crawler->filter($this->config['selectors']['price'])
                ->first()
                ->text('');
            $price = $this->extractPrice($priceText);

            if ($price === null) {
                return null;
            }

            $salePrice = null;
            if (!empty($this->config['selectors']['sale_price'])) {
                $salePriceText = $crawler->filter($this->config['selectors']['sale_price'])
                    ->first()->text('');
                $salePrice = $this->extractPrice($salePriceText);
            }

            $inStock = true;
            if (!empty($this->config['selectors']['in_stock'])) {
                $inStock = $crawler->filter($this->config['selectors']['in_stock'])->count() > 0;
            }

            return new PriceData(
                price: $price,
                salePrice: $salePrice,
                inStock: $inStock,
            );
        } catch (\Exception $e) {
            Log::warning("Price scrape failed for {$url}: {$e->getMessage()}");
            return null;
        }
    }

    private function extractPrice(string $text): ?float
    {
        $cleaned = preg_replace('/[^\d,.]/', '', str_replace(' ', '', $text));
        $cleaned = str_replace(',', '.', $cleaned);
        return is_numeric($cleaned) ? (float) $cleaned : null;
    }
}

Job עם גלאי שינויים

// app/Jobs/MonitorCompetitorPrice.php
class MonitorCompetitorPrice implements ShouldQueue
{
    public int $tries = 3;
    public array $backoff = [60, 120, 300];

    public function __construct(
        private int $productId,
        private int $competitorId,
        private string $competitorUrl
    ) {}

    public function handle(
        CompetitorPriceScraper $scraper,
        PriceChangeDetector $detector,
        RepricingEngine $repricer
    ): void {
        $config = Competitor::find($this->competitorId)->config;
        $priceData = $scraper->scrapePrice($this->competitorUrl);

        if ($priceData === null) return;

        // Сохранение текущей цены
        $record = CompetitorPrice::updateOrCreate(
            [
                'product_id' => $this->productId,
                'competitor_id' => $this->competitorId,
            ],
            [
                'price' => $priceData->price,
                'sale_price' => $priceData->salePrice,
                'in_stock' => $priceData->inStock,
                'scraped_at' => now(),
            ]
        );

        // Сохранение в историю (один раз в день)
        CompetitorPriceHistory::firstOrCreate(
            [
                'product_id' => $this->productId,
                'competitor_id' => $this->competitorId,
                'recorded_date' => today(),
            ],
            [
                'price' => $priceData->price,
                'in_stock' => $priceData->inStock,
            ]
        );

        // Детект изменений
        if ($record->wasChanged('price')) {
            $change = $detector->analyze($record);

            if ($change->isSignificant()) {
                Notification::route('mail', config('monitoring.alert_email'))
                    ->notify(new CompetitorPriceChangedNotification($record, $change));
            }

            // Автоперейценка
            if (config('repricing.enabled')) {
                $repricer->recalculate($this->productId);
            }
        }
    }
}

הגדרת לוח הזמנים לניטור

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

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

המנתח האוטומטי מעבד 1000 SKU ב-10 דקות, מהיר פי 40 מאיסוף ידני.

אילו נתונים נשמרים בהיסטוריית המחירים?

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

אסטרטגיות תמחור אוטומטיות

אסטרטגיה תיאור מתי להשתמש
beat_lowest הגדרת מחיר N דולר מתחת למינימום תפיסת נתח שוק אגרסיבית אם המרווח מאפשר
match_lowest התאמת המחיר הנמוך ביותר של המתחרה שמירת עמדה בנישות תחרותיות מאוד
beat_average מחיר N דולר מתחת לממוצע איזון בין מרווח לתחרותיות
percentile מחיר באחוזון נתון (לדוגמה, 25) שמירת מיצוב (פרימיום או תקציבי)

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

לוח מחוונים לניטור

מדדים מרכזיים להצגה:

מדד תיאור
מוצרים שבהם אנו יקרים יותר כמות ואחוז מהקטלוג
דלתא ממוצעת למינימום הפרש אחוז ממוצע מהמחיר הנמוך ביותר
מוצרים עם שינוי > 5% דורשים בדיקה ידנית
מוצרים ללא מלאי אצל מתחרים פוטנציאל להעלאת מחיר
לוח המחוונים עוזר לזהות במהירות חריגות, כמו שינוי מחיר פתאומי של מתחרה גדול.

טעויות נפוצות ביישום ניטור מחירים

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

איך להגדיר את הבוט ב-3 שלבים

  1. הוספת כתובות URL של מתחרים – ספקו כתובות URL לכל מוצר או תבנית עם SKU. אנו נגדיר סלקטורים ואינטגרציות API.
  2. הגדרת לוח זמנים לגרידה – הגדירו תדירות לכל מתחרה או קבוצת מוצרים (לדוגמה, כל שעתיים למוצרים מובילים, פעם ביום לאחרים).
  3. הגדרת חוקי תמחור – בחרו אסטרטגיה (beat, match, percentile) והגדירו ספי שינוי מינימליים (ברירת מחדל 0.5%). הבוט יעדכן את המחירים שלכם אוטומטית.

מה כלול בעבודה

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

לוח זמנים ומחירים

פיתוח מערכת בסיסית (מתחרה 1 + היסטוריה + התראות) אורך 4–6 ימי עסקים ומתחיל ב-$1,500. מערכת מלאה עם תמחור אוטומטי ולוח מחוונים ל-5+ מתחרים אורכת 10–14 ימים ומתחילה ב-$5,000. החיסכון מהפחתת עבודה ידנית בדרך כלל עולה על $2,000 בחודש. עבור קטלוג בינוני של 10,000 SKU, לקוחות מדווחים על חיסכון של 250 שעות בחודש, והעלאת מרווח נטו ב-3% תוך 3 חודשים. הזמינו מערכת ניטור מחירים מותאמת—צרו קשר להערכת הפרויקט שלכם.

דוגמת תצורה מפורטת עבור מתחרה טיפוסי, אנו מגדירים סלקטורים למחיר, מחיר מבצע, ומצב מלאי. הבוט משתמש ב-Playwright כדי לעבד JavaScript במידת הצורך. להלן דוגמת תצורה לאתר סטטי:
---
competitor:
  name: Example Shop
  base_url: ''
  selectors:
    price: '.price-amount'
    in_stock: '.in-stock'
  price_regex: '/[\d.,]+/'
  url_pattern: '/product/{sku}'
  requires_js: false
  request_delay: 1000

Playwright — תיעוד רשמי ב-playwright.dev