למה `requests` פשוט לא יספיק כאן

בואו נשים את זה על השולחן. הניסיון הראשון של כמעט כל מהנדס הוא לשלוח בקשת GET פשוטה. אבל באתרים כמו המשביר 365, מה שחוזר זה לא הדאטה. זו מעטפת HTML ריקה ו-bundle ענק של JavaScript. כל המידע על המוצרים, המחירים והמלאי נטען דינמית דרך קריאות API פנימיות (XHR/Fetch) אחרי שהדף הראשוני נטען. אם תסתכלו ב-Network Tab, תראו את זה קורה מול העיניים.

זו הסיבה שחייבים להשתמש ב-headless browser. אני לא מדבר על Selenium, שהפך לאיטי ומזוהה בקלות. אנחנו ב-2025, והבחירה הנכונה היא Playwright. הוא מהיר יותר, האוטומציות שלו אמינות יותר, והוא מגיע עם כלים מובנים שמקלים על החיים, כמו יכולות יירוט בקשות רשת. היכולת לחכות לאלמנט ספציפי או לבקשת רשת מסוימת לפני שממשיכים היא קריטית. בלי זה, אתם תחלצו דאטה חלקי או פשוט תיכשלו ב-90% מהריצות. המטרה הראשונית של איסוף קטלוג המשביר 365 דורשת עיבוד JavaScript מלא, ואין דרך לעקוף את זה. כל גישה אחרת היא בזבוז זמן ומשאבים.

ארכיטקטורה לאיסוף קטלוג מלא: תור ו-Workers

לקטלג את כל אתר המשביר 365 זה לא משהו שמריצים סקריפט אחד לינארי. אנחנו מדברים על קטלוג עם עשרות אלפי מוצרים, אולי אפילו יותר מ-50,000 SKUs. סריקה כזאת יכולה לקחת שעות. הפתרון היחיד שעובד ב-scale הוא ארכיטקטורת תור-עובדים (Queue-Worker). אני משתמש ב-Redis כתור וב-Celery לניהול ה-workers, אבל כלים דומים יעשו את העבודה.

התהליך פשוט: scraper ראשוני (crawler) עובר על עמודי הקטגוריות ודוחף את כל ה-URLs של המוצרים לתור. במקביל, צי של workers (נניח 10-15) שולף URLs מהתור ומעבד אותם במקביל. כל worker מריץ instance של Playwright. עם ארכיטקטורה כזו, אפשר להגיע לקצבים של 400-500 דפים בדקה, במקום עמוד כל כמה שניות. זה ההבדל בין פרויקט שלוקח יום שלם לפרויקט שלוקח שעה. המערכת הזו היא הבסיס לכל מודיעין מתחרים המשביר 365 רציני, כי היא מאפשרת דגימה מהירה ותדירה של כל הקטלוג. המטרה היא לאסוף שדות קריטיים כמו שמות מוצרים/מודעות ומפרטים בצורה עקבית ומלאה.

האתגר האמיתי: ניטור שינויים ומעקב מלאי

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

הגישה הנאיבית היא פשוט לסרוק הכל מחדש כל יום. זה לא יעיל. גישה טובה יותר היא לשמור 'snapshot' של כל מוצר (למשל, hash של ה-JSON עם נתוני המוצר) ולהשוות אותו בבדיקה הבאה. אם ה-hash לא השתנה, אין טעם לעדכן את הדאטהבייס. זה חוסך המון כתיבות מיותרות ומפשט את הלוגיקה. כשמדובר במעקב זמינות בסניפים, האתגר מורכב יותר. לעיתים קרובות, המידע הזה נטען בקריאת API נפרדת לאחר אינטראקציה של המשתמש (כמו בחירת סניף). צריך לזהות את אותה קריאת API, לשכפל אותה עבור כל סניף רלוונטי, ולעשות את זה בלי להעמיס יותר מדי על השרתים. כאן, טיפול בשגיאות 429 הופך להיות קריטי.

Failure Scenario: כשמבנה ה-DOM משתנה לך מתחת לרגליים

הנה תרחיש שקרה לי יותר מפעם אחת עם אתרים בסגנון המשביר 365. אתה בונה scraper מושלם שמבוסס על סלקטורים יציבים. למשל, div.product-card > span.price. הוא עובד נהדר במשך חודשיים, עם אחוזי הצלחה של 99.5%. ואז, בוקר אחד, אתה קם ומגלה ש-80% מהבקשות נכשלות או מחזירות null. מה קרה? צוות הפרונטאנד של האתר החליט לעשות A/B test קטן, או פשוט שינה את מבנה הקלאסים כחלק מריפקטור. עכשיו חצי מהמשתמשים מקבלים div.new-product-tile > div.price-tag > span.

הסלקטורים שלך שברויים. אם אין לך מערכת ניטור חכמה, אתה תגלה את זה רק אחרי ימים של איסוף דאטה פגום. הפתרון הוא לא להסתמך על סלקטור יחיד. צריך לבנות לוגיקה גמישה יותר: חפש טקסט שמכיל '₪', או השתמש בכמה סלקטורים אפשריים (fallback selectors). בנוסף, חובה להטמיע alerting. אם אחוז השדות הריקים עבור מחירים או זמינות קופץ מעל 5% בפרק זמן של שעה, אני מקבל התראה בסלאק. בלי מנגנון כזה, אתה עיוור. זה לא עניין של אם האתר ישתנה, אלא מתי.

מתי הגישה הזאת היא Overkill

בניית מערכת כזו היא השקעה משמעותית של זמן ומאמץ. לא תמיד היא נדרשת. אם כל מה שאתה צריך זה מחיר של 10-20 מוצרים פעם ביום, אז להרים מערך של workers עם Playwright זה כמו להשתמש בפטיש 5 קילו כדי לתקוע נעץ. במקרה כזה, סקריפט פשוט שמריץ Playwright באופן סדרתי, אולי אפילו מהמחשב המקומי שלך, יספיק בהחלט. אין צורך בתור, בניהול מצב מורכב או ב-proxy rotation מתוחכם.

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

הפיכת הנתונים הגולמיים ל-API שמיש

האיסוף הוא רק חצי מהסיפור. בסופו של יום, אף אחד לא רוצה לקבל קובץ CSV של 2GB כל בוקר. הלקוחות, בין אם הם פנימיים או חיצוניים, צריכים גישה נוחה למידע. המטרה הסופית היא בדרך כלל API / קובץ נתונים המשביר 365 שקל לעבוד איתו. אחרי שה-scrapers מסיימים את עבודתם ומאכלסים דאטהבייס (למשל, PostgreSQL), צריך לבנות שכבת API פשוטה מעל הנתונים.

אני מעדיף להשתמש ב-FastAPI בפייתון. הוא מהיר, קל ללמוד, ומייצר תיעוד אוטומטי (Swagger UI) שחוסך שעות של כתיבת דוקומנטציה. ה-API צריך לחשוף endpoints בסיסיים: קבלת מוצר לפי מזהה, חיפוש מוצרים, וקבלת היסטוריית מחירים למוצר ספציפי. נקודה חשובה נוספת היא ניקוי וסטנדרטיזציה של הנתונים. למשל, לוודא שכל שמות הקטגוריות אחידים, שהמחירים הם מספרים נקיים (בלי '₪' או פסיקים), ושהמפרטים הטכניים מפורמטים כ-JSON ולא כטקסט ארוך. העבודה הזו, שהיא פחות זוהרת, הופכת דאטה גולמי למוצר מידע בעל ערך אמיתי. כדי להגן על ה-scraper עצמו, כדאי להשתמש בטכניקות מתקדמות יותר, כמו שמתואר ב-מדריך Playwright stealth.