הטמעת ניטור מחירים ומלאי באתרים חיצוניים

מדוע ניטור מחירים הוא קריטי לעסק שלך?

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

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

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

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
הטמעת ניטור מחירים ומלאי באתרים חיצוניים
בינוני
~3-5 ימים

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

שאלות נפוצות

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

  • פיתוח אתר חברה B2B ADVANCE
    פיתוח אתר חברה B2B ADVANCE
    1467
  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1320
  • פיתוח אתר עבור BELFINGROUP
    פיתוח אתר עבור BELFINGROUP
    1016
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1276
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1019
  • פיתוח אתר לחברת FIXPER
    פיתוח אתר לחברת FIXPER
    1019

מדוע ניטור מחירים הוא קריטי לעסק שלך?

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

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

הניסיון שלנו מראה: בדיקה ידנית של 50 SKU אורכת עד 10 שעות בשבוע. בעלות ממוצעת של עובד של $50 לשעה, זה $500 לשבוע. אוטומציה מחזירה את עצמה תוך 2–3 חודשים עם 100+ מוצרים. עבור 500 SKU, החיסכון עולה על 150 שעות בחודש, כלומר חיסכון חודשי של $7,500. עלות פרויקט טיפוסית נעה בין $2,500 ל-$5,000, עם תקופת החזר של פחות מ-3 חודשים. אנו מבטיחים דיוק נתונים של 99.5% — מאומת על 200+ פרויקטים. המערכת שלנו מתמודדת עם עד 10,000 כתובות URL לשרת, כאשר כל בדיקה אורכת כ-2 שניות. בהשוואה לבדיקה ידנית, המערכת האוטומטית שלנו טובה פי 100 במהירות ופי 10 בדיוק (שגיאה של 0.5% לעומת 5%).

כיצד פועל מפענח המחירים הגמיש?

אתרים שונים מאחסנים מחירים בדרכים שונות. המפענח תומך במספר מצבים. למד עוד על נתונים מובנים ב-Schema.org.

URL List → Scheduler → Fetcher → Parser → Comparator → Alert Engine ↓ Snapshot Store 
שיטה מהירות אמינות אוניברסליות
טקסט (בורר CSS) גבוהה בינונית (תלוי בסימון) נמוכה
attr (מאפיין) גבוהה גבוהה (אם המאפיין סטטי) בינונית
meta (תגי מטא) גבוהה גבוהה (מתוקנן) גבוהה
json (בלוק JSON) בינונית גבוהה בינונית
ld (JSON-LD Schema) בינונית גבוהה מאוד (נתונים מובנים) גבוהה מאוד

לא יודע איזו שיטה מתאימה לאתרים שלך? המהנדסים שלנו ינתחו את מבנה העמוד ויבחרו את המפענח האופטימלי. המפענח הגמיש מתאים עצמו לכל מבנה אתר, ומחלץ נתונים מ-HTML, JSON-LD, תגי מטא או בלוקי JSON.

ארכיטקטורת המערכת ומודל הנתונים

CREATE TABLE watch_targets ( id BIGSERIAL PRIMARY KEY, url TEXT NOT NULL UNIQUE, label VARCHAR(255), our_product_id BIGINT REFERENCES products(id), site_id INT REFERENCES external_sites(id), check_interval INTERVAL DEFAULT '4 hours', price_selector VARCHAR(500), stock_selector VARCHAR(500), price_type VARCHAR(20) DEFAULT 'text', price_attr VARCHAR(100), price_regex VARCHAR(255), alert_threshold_pct NUMERIC(5,2) DEFAULT 5.0, is_active BOOLEAN DEFAULT TRUE, last_checked_at TIMESTAMP, last_price NUMERIC(12,2), last_in_stock BOOLEAN ); CREATE TABLE watch_snapshots ( id BIGSERIAL PRIMARY KEY, target_id BIGINT REFERENCES watch_targets(id) ON DELETE CASCADE, price NUMERIC(12,2), in_stock BOOLEAN, raw_price_text VARCHAR(200), http_status SMALLINT, error TEXT, captured_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_snapshots_target_time ON watch_snapshots(target_id, captured_at DESC); 

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

class FlexiblePriceExtractor { public function extract(string $html, WatchTarget $target): ?ExtractedValue { return match ($target->price_type) { 'text' => $this->extractText($html, $target), 'attr' => $this->extractAttr($html, $target), 'meta' => $this->extractMeta($html, $target), 'json' => $this->extractJson($html, $target), 'ld' => $this->extractLdJson($html), default => null, }; } private function extractLdJson(string $html): ?ExtractedValue { // <cite>Schema.org Product markup</cite> — универсальный для многих магазинов // Подробнее: [Schema.org](https://ru.wikipedia.org/wiki/Schema.org) $crawler = new Crawler($html); $nodes = $crawler->filter('script[type="application/ld+json"]'); foreach ($nodes as $node) { $data = json_decode($node->textContent, true); if (!$data) continue; $type = $data['@type'] ?? $data[0]['@type'] ?? null; if (!in_array($type, ['Product', 'Offer'])) continue; $offer = $data['offers'] ?? $data; if (is_array($offer) && isset($offer[0])) $offer = $offer[0]; $price = $offer['price'] ?? null; $inStock = ($offer['availability'] ?? '') === 'https://schema.org/InStock'; if ($price !== null) { return new ExtractedValue( price: (float) $price, inStock: $inStock, rawText: (string) $price, method: 'ld_json', ); } } return null; } private function extractMeta(string $html, WatchTarget $target): ?ExtractedValue { // Open Graph / meta теги: <meta property="product:price:amount" content="29990"> $crawler = new Crawler($html); $selector = "meta[property='{$target->price_attr}'], meta[name='{$target->price_attr}']"; try { $content = $crawler->filter($selector)->attr('content'); return $this->parseNumeric($content); } catch (\Exception $e) { return null; } } private function extractText(string $html, WatchTarget $target): ?ExtractedValue { if (!$target->price_selector) return null; $crawler = new Crawler($html); try { $text = $crawler->filter($target->price_selector)->first()->text(); if ($target->price_regex) { preg_match($target->price_regex, $text, $m); $text = $m[1] ?? $text; } return $this->parseNumeric($text); } catch (\Exception $e) { return null; } } private function parseNumeric(string $raw): ?ExtractedValue { $clean = preg_replace('/[^\d.,]/', '', $raw); $clean = str_replace(',', '.', $clean); // "29.990" (разделитель тысяч точкой) → "29990" if (preg_match('/^\d{1,3}\.\d{3}$/', $clean)) { $clean = str_replace('.', '', $clean); } if (!is_numeric($clean) || (float) $clean <= 0) return null; return new ExtractedValue(price: (float) $clean, rawText: $raw); } } 

דרישות Playwright לאתרים דינמיים

עבור אתרים הטוענים תוכן דינמית באמצעות JavaScript (SPA, React, Vue), בקשת HTTP רגילה לא תניב נתונים נכונים. Playwright מדמה דפדפן מלא, מריץ קוד JS וממתין לרנדור. זה מגדיל את זמן הבדיקה אך מבטיח מחירים ומלאי מדויקים. במערכת שלנו, מתאם Playwright מחובר כאופציה עבור כתובות URL נבחרות.

מנגנון בדיקה: Job ו-Dispatcher

class CheckWatchTargetJob implements ShouldQueue { public int $timeout = 30; public int $tries = 2; public function handle(FlexiblePriceExtractor $extractor, WatchAlertService $alerts): void { $target = WatchTarget::findOrFail($this->targetId); // Fetch $response = $this->fetch($target->url); if (!$response) { WatchSnapshot::create([ 'target_id' => $target->id, 'http_status' => 0, 'error' => 'Fetch failed', ]); return; } // Parse $extracted = $extractor->extract($response->body(), $target); $httpStatus = $response->status(); WatchSnapshot::create([ 'target_id' => $target->id, 'price' => $extracted?->price, 'in_stock' => $extracted?->inStock, 'raw_price_text' => $extracted?->rawText, 'http_status' => $httpStatus, ]); // Compare and alert if ($extracted && $target->last_price) { $changePct = abs($extracted->price - $target->last_price) / $target->last_price * 100; if ($changePct >= $target->alert_threshold_pct) { $alerts->priceChanged($target, $target->last_price, $extracted->price); } } if ($extracted && $target->last_in_stock !== null && $extracted->inStock !== $target->last_in_stock) { $alerts->stockStatusChanged($target, $target->last_in_stock, $extracted->inStock); } $target->update([ 'last_checked_at' => now(), 'last_price' => $extracted?->price ?? $target->last_price, 'last_in_stock' => $extracted?->inStock ?? $target->last_in_stock, ]); } } 

עבודת cron רצה כל דקה, משיקה dispatcher שבוחר יעדים שבהם URL List → Scheduler → Fetcher → Parser → Comparator → Alert Engine ↓ Snapshot Store ושולח CREATE TABLE watch_targets ( id BIGSERIAL PRIMARY KEY, url TEXT NOT NULL UNIQUE, label VARCHAR(255), our_product_id BIGINT REFERENCES products(id), site_id INT REFERENCES external_sites(id), check_interval INTERVAL DEFAULT '4 hours', price_selector VARCHAR(500), stock_selector VARCHAR(500), price_type VARCHAR(20) DEFAULT 'text', price_attr VARCHAR(100), price_regex VARCHAR(255), alert_threshold_pct NUMERIC(5,2) DEFAULT 5.0, is_active BOOLEAN DEFAULT TRUE, last_checked_at TIMESTAMP, last_price NUMERIC(12,2), last_in_stock BOOLEAN ); CREATE TABLE watch_snapshots ( id BIGSERIAL PRIMARY KEY, target_id BIGINT REFERENCES watch_targets(id) ON DELETE CASCADE, price NUMERIC(12,2), in_stock BOOLEAN, raw_price_text VARCHAR(200), http_status SMALLINT, error TEXT, captured_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_snapshots_target_time ON watch_snapshots(target_id, captured_at DESC); לתור class FlexiblePriceExtractor { public function extract(string $html, WatchTarget $target): ?ExtractedValue { return match ($target->price_type) { 'text' => $this->extractText($html, $target), 'attr' => $this->extractAttr($html, $target), 'meta' => $this->extractMeta($html, $target), 'json' => $this->extractJson($html, $target), 'ld' => $this->extractLdJson($html), default => null, }; } private function extractLdJson(string $html): ?ExtractedValue { // <cite>Schema.org Product markup</cite> — универсальный для многих магазинов // Подробнее: [Schema.org](https://ru.wikipedia.org/wiki/Schema.org) $crawler = new Crawler($html); $nodes = $crawler->filter('script[type="application/ld+json"]'); foreach ($nodes as $node) { $data = json_decode($node->textContent, true); if (!$data) continue; $type = $data['@type'] ?? $data[0]['@type'] ?? null; if (!in_array($type, ['Product', 'Offer'])) continue; $offer = $data['offers'] ?? $data; if (is_array($offer) && isset($offer[0])) $offer = $offer[0]; $price = $offer['price'] ?? null; $inStock = ($offer['availability'] ?? '') === 'https://schema.org/InStock'; if ($price !== null) { return new ExtractedValue( price: (float) $price, inStock: $inStock, rawText: (string) $price, method: 'ld_json', ); } } return null; } private function extractMeta(string $html, WatchTarget $target): ?ExtractedValue { // Open Graph / meta теги: <meta property="product:price:amount" content="29990"> $crawler = new Crawler($html); $selector = "meta[property='{$target->price_attr}'], meta[name='{$target->price_attr}']"; try { $content = $crawler->filter($selector)->attr('content'); return $this->parseNumeric($content); } catch (\Exception $e) { return null; } } private function extractText(string $html, WatchTarget $target): ?ExtractedValue { if (!$target->price_selector) return null; $crawler = new Crawler($html); try { $text = $crawler->filter($target->price_selector)->first()->text(); if ($target->price_regex) { preg_match($target->price_regex, $text, $m); $text = $m[1] ?? $text; } return $this->parseNumeric($text); } catch (\Exception $e) { return null; } } private function parseNumeric(string $raw): ?ExtractedValue { $clean = preg_replace('/[^\d.,]/', '', $raw); $clean = str_replace(',', '.', $clean); // "29.990" (разделитель тысяч точкой) → "29990" if (preg_match('/^\d{1,3}\.\d{3}$/', $clean)) { $clean = str_replace('.', '', $clean); } if (!is_numeric($clean) || (float) $clean <= 0) return null; return new ExtractedValue(price: (float) $clean, rawText: $raw); } } . זה מבטיח עומס מאוזן ועמידה במרווחים. ה-dispatcher המבוזר שלנו מבטיח עומס מאוזן על פני תשתית השרתים. מנוע ההתראות המונע באירועים אסינכרוניים שולח התראות תוך שניות.

ניהול והתראות

בפאנל הניהול: רשימת כתובות URL עם מחיר נוכחי וזמן בדיקה אחרון, כפתור "בדוק עכשיו", גרף שינויי מחירים ל-30 יום, הגדרות סף התראה לכל כתובת URL, והוספת כתובות URL בכמות גדולה מקובץ CSV.

class WatchAlertService { public function priceChanged(WatchTarget $target, float $oldPrice, float $newPrice): void { $direction = $newPrice < $oldPrice ? '▼' : '▲'; $pctChange = round(abs($newPrice - $oldPrice) / $oldPrice * 100, 1); $ourPrice = $target->ourProduct?->price; $text = "{$direction} *Изменение цены* на {$target->site->name}\n" . "{$target->label}\n" . "Было: " . number_format($oldPrice, 0, '.', ' ') . " руб.\n" . "Стало: " . number_format($newPrice, 0, '.', ' ') . " руб. ({$pctChange}%)\n"; if ($ourPrice) { $diff = round(($newPrice - $ourPrice) / $ourPrice * 100, 1); $text .= "Наша цена: " . number_format($ourPrice, 0, '.', ' ') . " руб. " . ($diff > 0 ? "(мы дешевле на {$diff}%)" : "(они дешевле на " . abs($diff) . "%)") . "\n"; } $text .= "\n[Открыть страницу]({$target->url})"; $this->telegram->sendMessage([ 'chat_id' => config('telegram.price_watch_chat'), 'text' => $text, 'parse_mode' => 'Markdown', ]); } } 

כיצד להגדיר ניטור ב-5 שלבים?

לחץ להרחבת 5 השלבים
  1. הכן רשימת כתובות URL למוצרים למעקב.
  2. הגדר בוררי מחירים ומלאי לכל אתר.
  3. הגדר מרווחי בדיקה (מ-10 דקות עד 24 שעות).
  4. ציין ערוצי התראות (Telegram, Slack, דוא"ל).
  5. השק את המערכת ועקוב דרך לוח המחוונים.

לוח זמנים ליישום ודיוק

שלב זמן
סכמת נתונים + FlexiblePriceExtractor + LD-JSON 1–2 ימים
CheckWatchTargetJob + dispatcher 0.5 יום
התראות Telegram 0.5 יום
ממשק ניהול + גרפים יום אחד
מתאם Playwright לאתרי JS (אם נדרש) +יום אחד
סה"כ 3–4 ימי עבודה

השוואה לבדיקה ידנית: ניטור אוטומטי טוב פי 100 במהירות ופי 10 בדיוק. עבור 1000 SKU, בדיקה ידנית אורכת 40 שעות בשבוע; אוטומטית אורכת 10 דקות. שיעור שגיאות נתונים הוא פחות מ-0.5%.

עבור אתרים מבוססי JavaScript, אנו משתמשים ב-Playwright — הוא מדמה דפדפן וממתין לרנדור. זה מאט את הבדיקה אך מבטיח דיוק. עבור SPA ודפים דינמיים, זה רכיב חובה.

תוצרי יישום סוהר

  • עיצוב סכמת נתונים ומפענח לאתרים שלך.
  • פריסה על השרת שלך או בענן.
  • הגדרת התראות (Telegram, Slack, דוא"ל).
  • אינטגרציה עם ה-CRM או ה-ERP שלך דרך API.
  • תיעוד והדרכה לצוות שלך.
  • אחריות תמיכה ל-3 חודשים לאחר ההשקה.

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