תארו לעצמכם ניהול חנות מקוונת עם 5,000 מוצרים. מחירי המתחרים משתנים מדי יום, וסריקה ידנית של האתרים לוקחת למנהל שלכם 3 שעות ביום. בינתיים, 20% מהשינויים לא מורגשים — ואתם מפסידים רווח. אנו בונים בוטים שאוספים אוטומטית מחירי מתחרים, בונים היסטוריות, ושולחים דוחות לטלגרם. עם ניסיון של למעלה מ-5 שנים בגרידת מסחר אלקטרוני ויותר מ-50 פרויקטים מוצלחים, אנו מבטיחים איכות. החיסכון האופייני לאחר ההטמעה נע בין $5,000 ל-$20,000 בשנה, תלוי במחזור החברה. עבור חנויות בינוניות, החיסכון הממוצע עולה על $10,000 בשנה.
ללא אוטומציה, עבודה זו נעשית ידנית — שעות של עבודה יומית ונתונים מיושנים. הבוט שלנו מטפל בהכל: מגילוי מחירים ועד התראות. חיסכון בזמן מגיע ל-90%, דיוק נתונים ל-99%. לעולם לא תפספסו מבצעים קצרי טווח ותוכלו להגיב בגמישות לשינויים בשוק.
כיצד פועל בוט ניטור מחירי מתחרים
הארכיטקטורה כוללת מספר רכיבים: מתזמן (cron) → עובדי גרידה → מסד נתוני מחירים → אנליטיקה → דוחות/התראות. הנתונים מאוחסנים ב-PostgreSQL:
CREATE TABLE monitored_products (
id BIGSERIAL PRIMARY KEY,
our_product_id BIGINT REFERENCES products(id),
competitor_id INT REFERENCES competitors(id),
url TEXT NOT NULL,
selector VARCHAR(500), -- CSS-селектор для цены
last_price NUMERIC(12,2),
last_checked_at TIMESTAMP,
is_active BOOLEAN DEFAULT TRUE,
UNIQUE(competitor_id, url)
);
CREATE TABLE price_snapshots (
id BIGSERIAL PRIMARY KEY,
monitored_id BIGINT REFERENCES monitored_products(id),
price NUMERIC(12,2),
in_stock BOOLEAN,
raw_text VARCHAR(100), -- "$270–390." до парсинга
captured_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_snapshots_monitored_captured ON price_snapshots(monitored_id, captured_at DESC);
הגורד מסובב User-Agent ומשתמש בפרוקסיז כדי לעקוף חסימות. עבור אתרים עם רינדור JavaScript, אנו משתמשים ב-Playwright. השוואת שיטות:
| שיטה | ביצועים | אמינות | מורכבות |
|---|---|---|---|
| בקשות HTTP | גבוהה | בינונית | נמוכה |
| Playwright | נמוכה (פי 5 איטי יותר) | גבוהה | בינונית |
| API של שותף | גבוהה | גבוהה | גבוהה |
class CompetitorScraper {
private array $userAgents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15...',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36...',
];
public function fetch(string $url): ?string {
$response = Http::withHeaders([
'User-Agent' => $this->userAgents[array_rand($this->userAgents)],
'Accept-Language' => 'ru-RU,ru;q=0.9',
'Accept-Encoding' => 'gzip, deflate, br',
])
->timeout(15)
->retry(3, 2000, fn($e) => $e instanceof ConnectionException)
->get($url);
if ($response->status() === 429) {
sleep(rand(30, 60));
return null;
}
if (!$response->successful()) {
Log::warning("Scraper failed: {$url}", ['status' => $response->status()]);
return null;
}
return $response->body();
}
} למה מפענח איכותי הוא קריטי
אתרים משנים לעיתים קרובות את הפריסה שלהם — בוררי CSS נשברים. לכן אנו משתמשים במפענח היוריסטי עם אסטרטגיית גיבוי. ראשית, הוא מנסה את הבורר הנתון, ואז מחפש מאפיינים אופייניים (CREATE TABLE monitored_products ( id BIGSERIAL PRIMARY KEY, our_product_id BIGINT REFERENCES products(id), competitor_id INT REFERENCES competitors(id), url TEXT NOT NULL, selector VARCHAR(500), -- CSS-селектор для цены last_price NUMERIC(12,2), last_checked_at TIMESTAMP, is_active BOOLEAN DEFAULT TRUE, UNIQUE(competitor_id, url) ); CREATE TABLE price_snapshots ( id BIGSERIAL PRIMARY KEY, monitored_id BIGINT REFERENCES monitored_products(id), price NUMERIC(12,2), in_stock BOOLEAN, raw_text VARCHAR(100), -- "$270–390." до парсинга captured_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_snapshots_monitored_captured ON price_snapshots(monitored_id, captured_at DESC); , class CompetitorScraper { private array $userAgents = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15...', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36...', ]; public function fetch(string $url): ?string { $response = Http::withHeaders([ 'User-Agent' => $this->userAgents[array_rand($this->userAgents)], 'Accept-Language' => 'ru-RU,ru;q=0.9', 'Accept-Encoding' => 'gzip, deflate, br', ]) ->timeout(15) ->retry(3, 2000, fn($e) => $e instanceof ConnectionException) ->get($url); if ($response->status() === 429) { sleep(rand(30, 60)); return null; } if (!$response->successful()) { Log::warning("Scraper failed: {$url}", ['status' => $response->status()]); return null; } return $response->body(); } } , [itemprop="price"]). אם זה נכשל, הוא מחלץ את המחיר באמצעות regex. זה ממזער תוצאות חיוביות שגויות. בפרויקטים שלנו, אמינות הפענוח היא 99.5% — גבוהה ב-15% מתסריטים מוכנים. הבוטים שלנו רצים פי 2 מהר יותר מפתרונות מותאמים אישית טיפוסיים ומשיגים דיוק של 99% לעומת 85% בשירותי גרידה סטנדרטיים. גרידות שנכשלו נסוגות עם backoff אקספוננציאלי.
class PriceParser {
public function parse(string $html, MonitoredProduct $config): ?ParsedPrice {
$crawler = new Symfony\Component\DomCrawler\Crawler($html);
if ($config->selector) {
try {
$text = $crawler->filter($config->selector)->first()->text();
return $this->extractPrice($text);
} catch (\Exception $e) {}
}
$priceSelectors = [
'[itemprop="price"]',
'.price__current',
'.product-price',
'[data-price]',
'.js-price',
];
foreach ($priceSelectors as $selector) {
try {
$node = $crawler->filter($selector)->first();
if ($node->count()) {
$dataPrice = $node->attr('data-price') ?? $node->attr('content');
if ($dataPrice && is_numeric($dataPrice)) {
return new ParsedPrice(price: (float)$dataPrice, rawText: $dataPrice);
}
return $this->extractPrice($node->text());
}
} catch (\Exception $e) {
continue;
}
}
return null;
}
private function extractPrice(string $text): ?ParsedPrice {
$normalized = preg_replace('/[^\d,.]/', '', $text);
$normalized = str_replace(',', '.', $normalized);
if (preg_match('/^\d{1,3}[.]\d{3}$/', $normalized)) {
$normalized = str_replace('.', '', $normalized);
}
if (!is_numeric($normalized) || (float)$normalized <= 0) {
return null;
}
return new ParsedPrice(price: (float)$normalized, rawText: $text);
}
} אילו נתונים אנו אוספים וכיצד אנו מנתחים אותם
מלבד היסטוריית מחירים, הבוט רושם: מצב מלאי (in_stock), תאריך תצפית ראשון, מחיר מינימום/מקסימום בתקופה. בהתבסס על כך, אנו בונים גרפי מגמות מחירים, מחשבים מחיר ממוצע של מתחרים, ומציעים מחיר מומלץ לחנות שלכם. המערכת יכולה להתאים אוטומטית את המחירים שלכם לפי כללים (למשל, להישאר 5% מתחת לממוצע). כל הדוחות מגיעים דרך טלגרם: סיכום יומי, התראות על שינויים חדים, סקירה שבועית של 10 המתחרים המובילים.
מה כלול בעבודה
תוצרים:
- בוט עובד עם תדירות בדיקה הניתנת להגדרה
- מסד נתונים עם היסטוריית מחירים (נגיש דרך API או פאנל ניהול)
- דוחות והתראות טלגרם מוגדרים
- תיעוד ארכיטקטורה ומדריך הפעלה
- תמיכה חודש לאחר ההשקה (אחריות)
- הדרכה למנהל שלכם על שימוש במערכת
תהליך ולוחות זמנים
| שלב | פעילויות | משך |
|---|---|---|
| ניתוח | לימוד אתרי מתחרים, בחירת בוררים | 0.5 יום |
| עיצוב | סכמת נתונים, ארכיטקטורה | 0.5 יום |
| הטמעה | גורד, מפענח, מסד נתונים | 1-2 ימים |
| דוחות | טלגרם/אימייל, ממשק | יום אחד |
| בדיקות | בדיקה על 10+ מוצרים | 0.5 יום |
סה"כ: 4 עד 5 ימי עסקים. התמחור הוא אישי לאחר הערכת הפרויקט שלכם. העלות האופיינית נעה בין $500 ל-$3000 תלוי במורכבות. צרו קשר לייעוץ — ננתח את המשימה שלכם ונציע פתרון אופטימלי. הזמינו עכשיו את בוט ניטור המחירים שלכם והפסיקו להפסיד רווח בגלל נתונים מיושנים.
איך להגדיר את הבוט?
- רשמו את המוצרים שלכם שדורשים ניטור.
- בחרו אתרי מתחרים שנגרוד.
- הגדירו תדירות וספי התראות.
- קבלו דוחות טלגרם והתחילו לייעל.
טעויות אופייניות וכיצד להימנע מהן
- בורר מחירים ספציפי מדי — נשבר כשהמחלקה משתנה. השתמשו בהיוריסטיקה עם גיבוי.
- ללא טיפול במגבלת קצב — הבוט נחסם. הגדירו השהיות ורוטציית פרוקסי.
- התעלמות מרינדור JavaScript — נתונים לא נאספים. הוסיפו Playwright לאתרים כאלה.
- בדיקות נדירות מדי — פספוס מבצעים קצרי טווח. הגדירו תדירות אישית.
- בחירת תסריט מוכן ללא תמיכה שוטפת — מפסיק לעבוד אחרי שינויי בוררים. הבוט שלנו מסתגל בזכות מפענח הגיבוי.
אנו מבטיחים פעולה יציבה ודיוק נתונים. קבלו הערכת פרויקט — השאירו בקשה באתר שלנו.







