ביקורת שלילית ב-Ozon או Wildberries יכולה להישאר ללא מענה במשך 24 שעות. בזמן הזה, היא יכולה להרתיע עשרות קונים פוטנציאליים. פיתחנו בוט שסורק ביקורות בזמן אמת ומודיע לצוות שלך באופן מיידי דרך Telegram. לפי הנתונים שלנו, 70% מהקונים משנים את דעתם על מותג לאחר תגובה מהירה לביקורת שלילית. הבוט שלנו מקצר את זמן התגובה משעות לדקות – הפחתה של 97%. במהלך השנים, ביצענו 30+ פרויקטים בניטור מוניטין – מפארסרים פשוטים ועד מערכות ארגוניות.
למה הבוט משתלם תוך חודש
בדיקה ידנית של 1000 כרטיסי מוצר במספר שווקים יכולה לקחת עד 4 שעות ביום. הבוט עושה את אותה עבודה בדקות ועולה השקעה חד-פעמית שמשתלמת תוך 1–2 חודשים דרך הפחתת עלויות עבודה והגדלת המרות. בפרויקט אחד למוכר אלקטרוניקה גדול, החלפנו ניטור ידני של 500 כרטיסים באוטומציה. זמן התגובה לביקורות שליליות ירד מ-4 שעות ל-2 דקות (מהיר ב-97%), וההמרה לנאמנות עלתה ב-15%. עם 10,000 ביקורות מעובדות בחודש, הבוט חוסך 200+ שעות עבודה ידנית.
בוט מהיר יותר מניטור ידני
בדיקה ידנית של עשרות כרטיסי מוצר בפלטפורמות מרובות לוקחת שעות. הבוט בודק כל פלטפורמה לפי לוח זמנים: עבור פלטפורמות עם API – פעם בשעה, עבור פארסינג – פעם בכל 4 שעות. הודעות מגיעות ל-Telegram תוך 1–2 דקות מהופעת הביקורת. זה מהיר פי 10–20 מהגישה הידנית.
| פרמטר | ידני | אוטומטי |
|---|---|---|
| זמן תגובה לשלילית | 2–24 שעות | 1–5 דקות |
| מספר כרטיסים שנבדקים ביום | עד 50 | ללא הגבלה |
| תדירות בדיקה | פעם ביום | כל שעה |
איך להגדיר את הבוט ב-3 שלבים
שלב 1: הכינו מקורות. אתם מספקים רשימה של כתובות URL של מוצרים או מפתחות API (עבור Yandex Market). אנו יוצרים רשומות ב-review_sources.
שלב 2: הפעילו מתאמים. הבוט מבצע פקודות reviews:check --platform=... לפי לוח זמנים. כל מתאם מיישם את ReviewAdapterInterface ומחזיר מערך של ReviewDTO.
שלב 3: הגדירו התראות. ציינו צ'אט Telegram לביקורות רגילות וצ'אט נפרד לדחופות (שליליות). הכל מוכן לשימוש.
ארכיטקטורת מתאמי פלטפורמה
כל פלטפורמה היא מתאם נפרד. עבור פלטפורמות עם API (Yandex Market), אנו משתמשים בבקשות ישירות; עבור אחרות, אנו מפארסים HTML דרך Playwright. כל המתאמים מיישמים ReviewAdapterInterface אחיד, מה שמקל על הוספת פלטפורמות חדשות. המערכת משתמשת בתור אסינכרוני עם Redis לניהול משימות ו-Supervisor לניטור תהליכים.
סכימת הנתונים כוללת שני טבלאות עיקריות: review_sources (קישורי מוצרים) ו-reviews (הביקורות עצמן). אינדקסים מאיצים את בחירת הביקורות שלא נקראו. הנה המבנה:
CREATE TABLE review_sources (
id BIGSERIAL PRIMARY KEY,
platform VARCHAR(50) NOT NULL, -- 'yandex_market', 'ozon', 'google', 'otzovik'
product_id BIGINT REFERENCES products(id),
external_url TEXT NOT NULL,
external_id VARCHAR(255), -- ID карточки на площадке
scrape_config JSONB,
is_active BOOLEAN DEFAULT TRUE,
UNIQUE(platform, external_url)
);
CREATE TABLE reviews (
id BIGSERIAL PRIMARY KEY,
source_id BIGINT REFERENCES review_sources(id),
external_id VARCHAR(255), -- ID отзыва на площадке
author VARCHAR(255),
rating SMALLINT, -- 1–5
text TEXT,
pros TEXT,
cons TEXT,
published_at TIMESTAMP,
discovered_at TIMESTAMP DEFAULT NOW(),
sentiment VARCHAR(20), -- 'positive', 'negative', 'neutral' (ML)
is_notified BOOLEAN DEFAULT FALSE,
UNIQUE(source_id, external_id)
);
CREATE INDEX idx_reviews_rating ON reviews(source_id, rating);
CREATE INDEX idx_reviews_notified ON reviews(source_id) WHERE is_notified = FALSE; API או פארסינג: השוואה
API יציב יותר, אבל לא כל הפלטפורמות פותחות אותו. Yandex Market מספק API לשותפים – ללא חסימות ונתונים מלאים. Ozon ו-Wildberries לא מציעות API לביקורות, לכן אנו משתמשים ב-Playwright: הדפדפן מרנדר את העמוד ומחלץ ביקורות. זה איטי יותר אבל אמין. אנו מיישמים לוגיקת ניסיון חוזר עם השהיה אקספוננציאלית כדי להתמודד עם תקלות זמניות.
הנה השוואה:
| מאפיין | API (Yandex Market) | פארסינג (Ozon/WB) |
|---|---|---|
| יציבות | גבוהה | בינונית (תלוי במבנה העמוד) |
| מהירות | מיידית | 2–5 שניות לעמוד |
| שלמות נתונים | כל השדות | מוגבל על ידי HTML |
| סיכון חסימה | אין | מינימלי עם השהיות סבירות (3–5 שניות בין בקשות) |
מתאמים עבור Yandex Market ו-Ozon:
class YandexMarketReviewAdapter implements ReviewAdapterInterface {
public function fetchReviews(ReviewSource $source): array {
$modelId = $source->external_id;
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . config('services.yandex_market.token'),
])->get("https://api.partner.market.yandex.ru/v2/models/{$modelId}/reviews", [
'count' => 30,
'page' => 1,
]);
return collect($response->json('result.reviews', []))
->map(fn($r) => new ReviewDTO(
externalId: (string) $r['id'],
author: $r['author']['name'] ?? 'Аноним',
rating: (int) $r['grade'],
text: $r['text'] ?? '',
pros: $r['pros'] ?? null,
cons: $r['cons'] ?? null,
publishedAt: Carbon::parse($r['date']),
))
->toArray();
}
}
class OzonReviewAdapter implements ReviewAdapterInterface {
public function fetchReviews(ReviewSource $source): array {
$data = $this->playwright->evaluate($source->external_url, <<<JS
await page.waitForSelector('[data-widget="webReviewProductScore"]', {timeout: 10000});
const items = document.querySelectorAll('[data-widget="webSingleReview"]');
return Array.from(items).map(el => ({
id: el.dataset.reviewId,
rating: parseInt(el.querySelector('[data-rating]')?.dataset.rating) || 0,
text: el.querySelector('.review-text')?.textContent?.trim() || '',
pros: el.querySelector('.pros')?.textContent?.trim() || null,
cons: el.querySelector('.cons')?.textContent?.trim() || null,
author: el.querySelector('.author-name')?.textContent?.trim() || 'Аноним',
date: el.querySelector('time')?.getAttribute('datetime'),
}));
JS);
return collect($data)->map(fn($r) => new ReviewDTO(
externalId: $r['id'],
author: $r['author'],
rating: $r['rating'],
text: $r['text'],
pros: $r['pros'],
cons: $r['cons'],
publishedAt: $r['date'] ? Carbon::parse($r['date']) : now(),
))->toArray();
}
} מנגנון ניתוח סנטימנט
אנו משתמשים בשתי רמות. אם הדירוג הוא 1–2 או 4–5, הסנטימנט ברור. עבור דירוג של 3, אנו מפעילים ניתוח מילות מפתח או AI:
class SentimentAnalyzer {
private array $negativeKeywords = [
'брак',
'сломан',
'не работает',
'возврат',
'обман',
'разочарован',
'ужас',
'кошмар',
'мусор',
'дрянь',
];
private array $positiveKeywords = [
'отлично',
'супер',
'доволен',
'рекомендую',
'превзошёл',
'быстро',
'качественно',
'спасибо',
];
public function analyze(ReviewDTO $review): string {
if ($review->rating <= 2) return 'negative';
if ($review->rating >= 4) return 'positive';
$text = mb_strtolower($review->text . ' ' . $review->cons);
foreach ($this->negativeKeywords as $kw) {
if (str_contains($text, $kw)) return 'negative';
}
return 'neutral';
}
public function analyzeWithAI(string $text): string {
$response = $this->openai->chat()->create([
'model' => 'gpt-4o-mini',
'messages' => [
['role' => 'system', 'content' => 'Определи тональность отзыва. Ответь одним словом: positive, negative или neutral.'],
['role' => 'user', 'content' => $text],
],
'max_tokens' => 10,
]);
return in_array($response->choices[0]->message->content, ['positive', 'negative', 'neutral']) ? $response->choices[0]->message->content : 'neutral';
}
}התראות נשלחות ל-Telegram: עבור ביקורות שליליות – לצ'אט תמיכה דחוף נפרד, עבור אחרות – לצ'אט הכללי. ההודעה כוללת דירוג, טקסט הביקורת וקישור.
class ReviewNotifier {
public function notifyNew(Review $review): void {
$emoji = match ($review->sentiment) {
'positive' => '⭐',
'negative' => '🚨',
default => '💬',
};
$stars = str_repeat('★', $review->rating) . str_repeat('☆', 5 - $review->rating);
$text = "{$emoji} *Новый отзыв* — {$review->source->platform}\n" .
"{$stars} {$review->rating}/5\n" .
"*{$review->author}*\n\n" .
mb_substr($review->text, 0, 300) . (mb_strlen($review->text) > 300 ? '...' : '') . "\n\n" .
"[Открыть отзыв]({$review->source->external_url})";
$chatId = $review->sentiment === 'negative' ? config('telegram.urgent_reviews_chat') : config('telegram.reviews_chat');
$this->telegram->sendMessage([
'chat_id' => $chatId,
'text' => $text,
'parse_mode' => 'Markdown',
]);
$review->update(['is_notified' => true]);
}
}אנליטיקת דירוגים ולוח זמנים לבדיקה:
-- Агрегат рейтинга по платформам за последние 30 дней
SELECT rs.platform,
COUNT(*) AS total_reviews,
ROUND(AVG(r.rating), 2) AS avg_rating,
COUNT(*) FILTER (WHERE r.rating <= 2) AS negative_count,
COUNT(*) FILTER (WHERE r.rating >= 4) AS positive_count
FROM reviews r
JOIN review_sources rs ON r.source_id = rs.id
WHERE r.published_at >= NOW() - INTERVAL '30 days'
GROUP BY rs.platform
ORDER BY avg_rating;
-- Быстрые платформы с API — каждый час
$schedule->command('reviews:check --platform=yandex_market')->hourly();
-- Парсинг через браузер — каждые 4 часа (ресурсоёмко)
$schedule->command('reviews:check --platform=ozon')->everyFourHours();
$schedule->command('reviews:check --platform=wildberries')->everyFourHours();
-- Еженедельный сводный отчёт с трендом рейтинга
$schedule->job(new WeeklyReviewsReportJob)->weekly()->mondays()->at('09:00');
מה אם הפלטפורמה משנה את מבנה ה-HTML שלה?
פארסינג תלוי בפריסה. כשהסלקטורים משתנים, המתאם מפסיק לעבוד. בנינו ניטור: פעם ביום, הבוט בודק שהמתאם מחזיר תוצאה לא ריקה. אם יש שגיאה – התראה דרך Telegram. אנו מעדכנים סלקטורים במהירות. החוזה שלנו כולל שבועיים של תמיכה לאחר השחרור שבמהלכם המתאמים מותאמים בחינם.
מה כלול בעבודה?
הפרויקט המלא כולל: עיצוב סכימת נתונים, פיתוח מתאמים לשלוש פלטפורמות, הגדרת לוח זמנים, יישום ניתוח סנטימנט, התראות Telegram, לוח מחוונים אנליטי בפאנל הניהול. ציר זמן: גרסה בסיסית – יומיים, חבילה מלאה – עד 5 ימי עסקים. העלות מחושבת באופן אישי לפי המחסנית שלכם ומספר הפלטפורמות. אנו מבטיחים פעולה יציבה של הבוט כל עוד מכבדים את מגבלות הפלטפורמה.
צרו קשר – נעריך את הפרויקט שלכם ביום עסקים אחד. קבלו ייעוץ ממהנדס.







