בניית צינור גרידה אמין עם תורי משימות

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

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

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי 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

ראינו שוב ושוב כיצד לולאת גרידה מתפרקת בשגיאת הרשת הראשונה. אלפי שורות אובדות, והניפוי אורך שעות. תור משימות לגרידה פותר שלוש בעיות יסודיות: בידוד כשלים, ניסיונות חוזרים אוטומטיים, וקנה מידה אופקי של עובדים. בפרויקט אחד עם 50,000 דפי קטלוג, עברנו מסקריפט ליניארי ל-BullMQ — זמן הביצוע נחתך בחצי, ואובדן הנתונים ירד לאפס. בבדיקות שלנו, BullMQ מבצע פי 2 טוב יותר מסקריפטים ליניאריים לסריקה רציפה. עיכוב ההתאוששות הממוצע לאחר כשל הוא 60 שניות הודות לנסיגה אקספוננציאלית. התקציב ליישום תור משימות נע בדרך כלל מבינוני למשמעותי, תלוי במורכבות ובנפח הנתונים. עלות היישום האופיינית נעה בין $2,000 ל-$4,000 לפרויקטים בינוניים, עם חיסכון חודשי ממוצע של $2,000–$5,000 מהפחתת ניסיונות חוזרים ועבודה ידנית. לדוגמה, יישום עבור לקוח בינוני עלה $3,500 וחסך $4,000 בחודש.

איזו בעיה פותר התור?

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

איך לבחור Broker?

עבור רוב פרויקטי ה-web, BullMQ או Celery הם אופטימליים. BullMQ רץ על Redis, מציע ממשק UI בשם Board לניטור, תומך בעדיפויות, ומטפל בעד 100,000 משימות ביום על מופע יחיד. Celery מתאים יותר לסטacks של Python: שרשראות משימות ועיבוד קבוצתי נבנים ללא קוד נוסף. RabbitMQ מוצדק במערכות בעומס גבוה שבהן נדרש ניתוב מורכב באמצעות routing keys ואספקה מובטחת ברמת AMQP — לדוגמה, בעת איגום נתונים מ-20+ מקורות במהירויות שונות. התיעוד הרשמי של RabbitMQ ממליץ על DLQ לנתונים קריטיים. בדיקות ביצועים מראות ש-BullMQ מעבד משימות עד פי 2.5 מהר יותר מ-Celery עבור עומסי עבודה זהים.

השווה את התכונות:

תכונה BullMQ Celery RabbitMQ
Backend Redis Redis/RabbitMQ AMQP
תפוקה מקסימלית ~100k/יום ~50k/יום >200k/יום (cluster)
ממשק UI מובנה כן (Board) Flower כן (Management)
מורכבות הגדרה נמוכה בינונית גבוהה

BullMQ: הגדרת עובדים וניסיונות חוזרים

import { Queue, Worker, Job } from 'bullmq'; import { Redis } from 'ioredis'; const connection = new Redis({ host: 'localhost', port: 6379, maxRetriesPerRequest: null }); // Создание очереди export const scrapeQueue = new Queue('scraping', { connection, defaultJobOptions: { attempts: 3, backoff: { type: 'exponential', delay: 60_000 }, removeOnComplete: { count: 500 }, removeOnFail: { count: 200 }, }, }); // Добавление задачи await scrapeQueue.add('scrape-url', { url: 'https://example.com/catalog?page=5', siteId: 42, depth: 1, }, { priority: 1 }); // Воркер const worker = new Worker('scraping', async (job: Job) => { const { url, siteId } = job.data; const html = await fetchWithProxy(url); const products = parseProducts(html); await saveProducts(products, siteId); return { count: products.length }; }, { connection, concurrency: 5 }); worker.on('failed', (job, err) => { logger.error(`Job ${job?.id} failed: ${err.message}`); }); 

Celery: pipeline עם שרשראות

from celery import Celery, chain, chord import redis app = Celery('scraper', broker='redis://localhost:6379/0', backend='redis://localhost:6379/1') app.conf.task_routes = { 'scraper.tasks.fetch_listing': {'queue': 'listings'}, 'scraper.tasks.fetch_product': {'queue': 'products'}, } @app.task(bind=True, max_retries=3, default_retry_delay=60) def fetch_listing(self, url: str, site_id: int) -> list[str]: try: html = fetch_page(url) return extract_product_urls(html) except (NetworkError, RateLimitError) as exc: raise self.retry(exc=exc, countdown=2 ** self.request.retries * 60) @app.task(bind=True, max_retries=3) def fetch_product(self, url: str, site_id: int) -> dict: try: html = fetch_page(url) return parse_product(html) except Exception as exc: raise self.retry(exc=exc) @app.task def save_products(products: list[dict], site_id: int): bulk_upsert(products, site_id) # Запуск пайплайна def start_site_crawl(site_id: int, catalog_url: str): urls = fetch_listing.delay(catalog_url, site_id).get() chord( fetch_product.s(url, site_id) for url in urls )(save_products.s(site_id)) 
דוגמה לתצורת Celery עם הגבלת קצב
app.conf.task_annotations = { 'scraper.tasks.fetch_product': { 'rate_limit': '10/m' } } 

זה מגביל משימות fetch_product ל-10 לדקה לכל עובד, ועוזר למנוע חסימת IP.

Dead Letter Queue: הגדרה וניתוח

משימות שממצות את כל הניסיונות עוברות ל-Dead Letter Queue. זה לא רק פח אשפה — זה תור לניתוח ידני ועיבוד חוזר. ב-RabbitMQ, DLQ מוגדר באמצעות ארגומנטים של תור:

channel.queue_declare( queue='scraping.products', durable=True, arguments={ 'x-dead-letter-exchange': 'scraping.dlx', 'x-dead-letter-routing-key': 'failed', 'x-message-ttl': 3600000, # 1 час } ) channel.exchange_declare(exchange='scraping.dlx', exchange_type='direct') channel.queue_declare(queue='scraping.failed', durable=True) channel.queue_bind(queue='scraping.failed', exchange='scraping.dlx', routing_key='failed') 

ניתן לנתב מחדש משימות ב-DLQ לתור הראשי לאחר תיקון סיבת הכשל — דרך ממשק Admin או סקריפט. ב-BullMQ, DLQ מיושם עם תור נפרד ו-handler לכשלים.

השוואת אסטרטגיות ניסיונות חוזרים

אסטרטגיה עיכוב מתי להשתמש
אקספוננציאלית 2^retry * base שגיאות רשת זמניות
ליניארית retry * base הגבלת קצב
קבועה עיכוב קבוע תנאים יציבים

ניטור תור

BullMQ Board (ממשק UI ל-BullMQ) או Flower (עבור Celery) נותן ייצוג חזותי של מצב התור. מדדים מרכזיים למעקב:

  • עומק התור (משימות ממתינות)
  • מהירות עיבוד (משימות/שנייה)
  • שיעור שגיאות לפי סוג משימה
  • זמן ביצוע (p50, p95, p99)

מדדים אלה מיוצאים ל-Prometheus דרך נקודת הקצה import { Queue, Worker, Job } from 'bullmq'; import { Redis } from 'ioredis'; const connection = new Redis({ host: 'localhost', port: 6379, maxRetriesPerRequest: null }); // Создание очереди export const scrapeQueue = new Queue('scraping', { connection, defaultJobOptions: { attempts: 3, backoff: { type: 'exponential', delay: 60_000 }, removeOnComplete: { count: 500 }, removeOnFail: { count: 200 }, }, }); // Добавление задачи await scrapeQueue.add('scrape-url', { url: 'https://example.com/catalog?page=5', siteId: 42, depth: 1, }, { priority: 1 }); // Воркер const worker = new Worker('scraping', async (job: Job) => { const { url, siteId } = job.data; const html = await fetchWithProxy(url); const products = parseProducts(html); await saveProducts(products, siteId); return { count: products.length }; }, { connection, concurrency: 5 }); worker.on('failed', (job, err) => { logger.error(`Job ${job?.id} failed: ${err.message}`); }); ומוצגים ב-Grafana. זמן התגובה הממוצע של הפרוסרים שלנו ירד ב-35% לאחר הצגת הניטור.

תהליך

  1. ניתוח: קביעת נפח נתונים, תדירות גרידה, דרישות אמינות.
  2. עיצוב: בחירת broker, סכמת משימות, הגדרות ניסיונות חוזרים.
  3. יישום: כתיבת עובדים, DLQ, שילוב ניטור.
  4. בדיקות: הרצת בדיקות עומס, אימות התנהגות כשלים.
  5. פריסה: פריסה על שרת או Kubernetes, הגדרת CI/CD.

מה כלול

  • הגדרת תור (BullMQ/Celery/RabbitMQ) עם מדיניות ניסיונות חוזרים ו-DLQ
  • שילוב עם Redis (Sentinel/Cluster) או RabbitMQ
  • ניטור (Prometheus + Grafana) והתראות
  • תיעוד תפעולי והדרכת צוות
  • אחריות לחודש אחד לאחר המסירה

יש לנו ניסיון של 6+ שנים במערכות גרידה ומסרנו למעלה מ-30 פרויקטים עם תורים. עיבדנו למעלה מ-10 מיליון משימות גרידה בפרויקטים שלנו עם זמינות של 99.9%. קבל ייעוץ חינם מהמהנדס שלנו — נעריך את הפרויקט שלך ביום אחד ונציע את הארכיטקטורה האופטימלית.

לוח זמנים

תור בסיסי עם ניסיונות חוזרים ו-DLQ — 3–4 ימי עסקים. הוספת מדדים, ממשק UI ו-clustering — עוד 2–3 ימים. העלות הסופית נקבעת באופן אישי לפי נפח הנתונים שלך.

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