ארכיטקטורה ראשונית: למה Headless Browser הוא ברירת המחדל
הצעד הראשון בכל פרויקט הוא להבין את המטרה. אתר כמו אושר עד הוא לא בלוג סטטי. הוא יישום ווב דינמי (SPA) שמייצר את התוכן בצד הלקוח. פתיחת ה-DevTools בכרטיסיית הרשת מגלה את האמת מהר מאוד: התוכן, ובמיוחד הנתונים החשובים כמו מחירים וזמינות, לא מגיעים ב-HTML הראשוני. הם נטענים דרך קריאות API אסינכרוניות שמופעלות על ידי סקריפטים. המשמעות היא שכל ניסיון לגשת ישירות ל-URL של מוצר עם httpx יחזיר מעטפת HTML ריקה מתוכן.
לכן, נקודת הפתיחה שלנו היא לא שאלה של אם להשתמש ב-headless browser, אלא איך. תפסיקו עם Selenium לפרויקטים חדשים. Playwright מנצח אותו ב-2025 בכל מטריקה רלוונטית — מהירות, יציבות, וה-API שלו פשוט נקי יותר. הארכיטקטורה הנכונה מתחילה עם Playwright שמנוהל על ידי תזמור (orchestration) שיודע לפזר עבודה על פני מספר workers. המטרה הראשונית היא לאסוף את כל קטלוג המוצרים, שמכיל להערכתי בין 25,000 ל-35,000 מק"טים ייחודיים. זהו הבסיס לכל פעולה בהמשך, החל מאיסוף קטלוג ועד לניטור מחירים יומי.
אתגר הסניפים והמלאי: פיצוח הלוגיקה הגיאוגרפית
אחד המכשולים הגדולים ביותר בסקרייפינג של רשתות סופרמרקטים הוא נתונים מבוססי מיקום. המחיר או המבצע שאתה רואה בתל אביב לא בהכרח זהה לזה שבאילת. אושר עד, כמו רוב הרשתות, מתאים את עצמו לסניף הנבחר. זה לא פיצ'ר, זו דרישת ליבה של המודל העסקי שלהם, וזה סיוט ל-scraper.
הפתרון הוא לא לנסות "לנחש" את ה-API. צריך לבצע הנדסה לאחור של התהליך שהדפדפן עובר. בדרך כלל, בחירת סניף מאחסנת מזהה כלשהו (store ID) ב-localStorage, ב-sessionStorage או בקוקי. ה-scraper חייב לחקות את ההתנהגות הזו. לפני כל בקשה לנתוני מוצר, צריך לוודא שה-context של הדפדפן מוגדר לסניף הנכון. זה אומר שצריך לנהל session נפרד לכל סניף, או לאתחל את ה-state לפני כל קבוצת בקשות. פרויקט מעקב מלאי/זמינות אושר עד לא יכול להתקיים בלי היכולת הזו. צריך למפות את כל מזהי הסניפים (בדרך כלל יש קריאת API ייעודית שמחזירה אותם) ולבצע איטרציה עליהם. ניסיון לאסוף נתונים בלי context של סניף יספק במקרה הטוב נתוני ברירת מחדל, ובמקרה הרע פשוט יחזיר שגיאות.
מערכת ניטור מחירים יציבה: קצב, פרוקסיז, וטיפול בשגיאות
כשיש לנו את רשימת המוצרים והבנה של לוגיקת הסניפים, אפשר להתחיל לבנות את מערך ה-ניטור מחירים אושר עד. כאן נכנסים האתגרים של סקייל. אי אפשר לשלוח 30,000 בקשות מכרטיס רשת בודד ולצפות שזה יעבוד. מערכות הגנה מזהות דפוסים כאלה תוך דקות. המפתח הוא proxy rotation חכם. אני לא מדבר על רשימה של 10 פרוקסיז חינמיים. אני מדבר על מאגר גדול של פרוקסיז מסוג residential שמאפשרים פיזור תעבורה רחב.
מבחינת קצב, כלל אצבע טוב הוא לא לעבור 30-40 בקשות לדקה מאותה כתובת IP. עם מאגר של 100 כתובות IP, אפשר להגיע לקצב מכובד בלי להפעיל אזעקות. המטרה היא להגיע לאחוזי הצלחה של 98%-99% באופן עקבי. כל מה שמתחת ל-95% מצביע על בעיה בניהול הפרוקסיז או בזיהוי טביעת האצבע של הדפדפן. בנוסף, חובה לממש לוגיקת retry עם exponential backoff. כשנתקלים בשגיאת 429 (Too Many Requests) או חסימת CAPTCHA, הדרך הנכונה היא לא לנסות שוב מיד, אלא לסמן את ה-IP כ"שרוף" זמנית, להחליף אותו, ולהכניס את הבקשה חזרה לתור עם השהייה. טיפול נכון בשגיאות 429 הוא מה שמבדיל בין scraper שמקרטע לבין מערכת דאטה אמינה.
איפה רוב ה-Scrapers נכשלים: כשלא מבינים את ה-JavaScript
זה התרחיש שראיתי קורה שוב ושוב: מהנדס מזהה קריאת API שמחזירה JSON עם נתוני מוצר. הוא חושב שמצא את מכרה הזהב. הוא בונה scraper מהיר ויעיל עם httpx שמכה ישירות ב-endpoint הזה, עוקף את הצורך בדפדפן כבד. זה עובד. במשך שלושה ימים. ביום הרביעי, כל הבקשות מתחילות להחזיר 403 Forbidden. מה קרה?
מה שקרה הוא שהאתר משתמש בטוקנים זמניים או חתימות שנוצרות על ידי JavaScript בצד הלקוח. סקריפט שרץ בדפדפן מייצר header מיוחד (למשל, x-csrf-token או חתימה מורכבת יותר) שמצורף לכל קריאת API. ה-scraper הפשוט לא מריץ את ה-JS, ולכן לא מייצר את הטוקן המעודכן, והשרת דוחה אותו. זהו failure mode קלאסי באתרים מודרניים. הניסיון לעשות הנדסה הפוכה לסקריפטים האלה הוא בדרך כלל בזבוז זמן עצום. הם עוברים שינויים, עוברים מיניפיקציה ואובפוסקציה, והתחזוקה של זה הופכת לסיוט. זו הסיבה שגישת ה-headless browser, למרות שהיא איטית יותר פר בקשה, היא יציבה ואמינה יותר לאורך זמן. היא פשוט מריצה את כל הלוגיקה שהאתר מצפה שתרוץ. אם אתם בכל זאת מתעקשים על גישה ישירה, תצטרכו להשקיע מאמץ משמעותי בהבנת טכניקות עקיפה מתקדמות.
השלב הסופי: מנתונים גולמיים ל-API שמיש
איסוף הדאטה הוא רק חצי מהעבודה. הנתונים שחולצו מאושר עד הם גולמיים, מבולגנים ולעיתים לא עקביים. השלב הבא, והחשוב לא פחות, הוא לבנות צינור עיבוד נתונים (data pipeline) שהופך את הכאוס הזה לנכס. זה מכסה את מקרי השימוש של מודיעין מתחרים אושר עד ו-API / קובץ נתונים אושר עד.
הצינור הזה צריך לבצע מספר פעולות קריטיות: ניקוי (למשל, הסרת תגיות HTML משמות מוצרים), נורמליזציה (המרת מחירים למבנה מספרי אחיד, פירוק יחידות מידה), והעשרה (שיוך מוצרים לקטגוריות פנימיות). בסופו של דבר, הלקוח הפנימי או החיצוני לא רוצה לקבל קובץ JSON של 3GB כל בוקר. הוא רוצה גישה פשוטה למידע. התוצר הסופי צריך להיות API נקי או קובץ CSV/Parquet מסודר שעולה למאגר נתונים כמו S3 או BigQuery. למשל, לספק endpoint שמקבל מק"ט ומחזיר את היסטוריית המחיר שלו בכל הסניפים בשבוע האחרון. זהו הערך האמיתי. ה-scraping הוא רק האמצעי, לא המטרה. בניית ה-pipeline הזה דורשת חשיבה על מבני נתונים, בסיסי נתונים, ואיך לתמוך בשאילתות שהמשתמשים באמת צריכים.
