ארכיטקטורת היעד: למה requests ו-BeautifulSoup לא יספיקו

הדבר הראשון שחייבים להבין לגבי שופרסל הוא שהתוכן לא נמצא ב-HTML הראשוני. כמו רוב אתרי האיקומרס המודרניים, מדובר באפליקציית צד-לקוח (כנראה React או Vue) שמושכת נתונים דרך קריאות API פנימיות. אם תעשה curl ל-URL של קטגוריה, תקבל מעטפת HTML ריקה ושלד של JavaScript. כל המידע – שמות מוצרים, מחירים, מבצעים – נטען דינמית לאחר מכן.

זה פוסל מיד את הגישה הקלאסית. הניסיון לאתר את ה-API הפנימי ולחקות את הקריאות הוא מסלול מפתה, אבל לרוב הוא שביר מאוד. ה-endpoints האלה לא מתועדים, הם דורשים headers ספציפיים, טוקנים של session, ולפעמים חתימות שנוצרות על ידי קוד JS שעבר obfuscation. כל עדכון קטן בצד הלקוח יכול לשבור לך את כל הלוגיקה. ראיתי צוותים מבזבזים שבועות על הנדסה לאחור של API פנימי, רק כדי לגלות שהוא השתנה חודש אחרי.

הקטלוג עצמו מכיל עשרות אלפי מוצרים, עם הערכה של מעל 50,000 SKUs שונים הפרוסים על פני מאות קטגוריות ותתי-קטגוריות. לכן, הפתרון חייב להיות מסוגל לרנדר JavaScript. זה משאיר אותנו עם אופציה אחת ריאלית: שליטה בדפדפן אמיתי. כאן נכנסים כלים כמו Playwright או Puppeteer. הם לא רק מורידים HTML, הם מריצים דפדפן מלא (headless Chrome/Firefox) שמבצע את כל קריאות ה-API, מרנדר את התוכן ומאפשר לנו גישה ל-DOM הסופי – בדיוק כפי שמשתמש אנושי רואה אותו.

הסטאק הנכון: Playwright, Stealth וניהול חכם של Sessions

אז החלטנו על דפדפן headless. השלב הבא הוא לבחור את הכלי הנכון ולבנות סביבו. תפסיקו עם Selenium לפרויקטים חדשים. Playwright מנצח אותו ב-2025 כמעט בכל מדד רלוונטי: מהירות, יציבות, וה-API שלו פשוט נקי ונוח יותר. הוא מגיע עם יכולות מובנות לחכות לאלמנטים, ליירט בקשות רשת ולנהל contexts של דפדפן בצורה אלגנטית.

אבל התקנה בסיסית של Playwright לא תספיק. אתרים כמו שופרסל משתמשים בסקריפטים לזיהוי בוטים (fingerprinting) שבודקים עשרות פרמטרים של הדפדפן: החל מה-User-Agent ועד למאפיינים של WebGL, פונטים מותקנים, והתנהגות של ה-JavaScript engine. אם אחת הבדיקות נכשלת, אתה מסומן. כאן נכנס לתמונה מדריך Playwright stealth. שימוש בתוספי stealth פותר כ-80% מבעיות הזיהוי הבסיסיות על ידי שינוי מאפייני הדפדפן כדי שייראה אנושי ואורגני.

ניהול sessions הוא החלק השני של המשוואה. אל תשתמשו באותו context של דפדפן ליותר מדי בקשות. כל session צריך להיראות כמו משתמש נפרד. זה אומר IP שונה, cookies נקיים, ו-fingerprint מעט שונה. תכנון נכון יאפשר לכם להריץ עשרות sessions במקביל, מה שמוריד דרמטית את זמן הריצה הכולל עבור איסוף קטלוג שופרסל מלא.

משחק הפרוקסים וה-Fingerprints: איך להישאר מתחת לרדאר

בואו נהיה ברורים: אם אתם מנסים לבצע scraping לשופרסל מ-IP של שרת בענן (AWS, GCP, Azure), אתם תיחסמו. כנראה תוך פחות מ-100 בקשות. טווחי ה-IP האלה מסומנים ומוכרים. הפתרון היחיד שעובד בקנה מידה הוא שימוש ברשת פרוקסים איכותית. ולא סתם פרוקסי, אלא פרוקסי residencial.

ההבדל הוא קריטי. פרוקסי דאטה-סנטר הוא קל לזיהוי. פרוקסי residencial מנתב את התעבורה שלכם דרך מכשירים אמיתיים של משתמשי קצה, מה שגורם לבקשות שלכם להיראות כאילו הן מגיעות מבתים רגילים. זה מקשה משמעותית על מערכות ההגנה להבדיל בין ה-scraper שלכם לבין תעבורה לגיטימית. המטרה היא לא רק להחליף IP, אלא להתאים את ה-IP למיקום הגאוגרפי הרלוונטי (ישראל, במקרה הזה) ולבצע רוטציה חכמה. רוטציה אחרי כל בקשה היא טעות; היא נראית חשודה. רוטציה כל כמה דקות או פר session היא גישה טובה יותר.

במקביל, חייבים לטפל ב-rate limiting. אל תנסו "להפציץ" את השרת. scraper טוב הוא scraper סבלני. התחילו עם קצב נמוך, נגיד בקשה כל 5-10 שניות, ונטרו את אחוזי ההצלחה. אם אתם מתחילים לקבל יותר מדי שגיאות 429 או CAPTCHAs, זה סימן להאט. מערכת טובה צריכה לשאוף ל-98%-99% הצלחה. כל דבר מתחת ל-95% אומר שמשהו בסיסי בסטאפ שלכם שבור. אם אתם נתקלים בחסימות תכופות, קראו על טיפול בשגיאות 429 לפני שאתם ממשיכים.

תרחיש כישלון קלאסי: מלכודת בחירת הסניף והמלאי

הנה טעות שראיתי אצל רבים שמנסים לעשות scraping לאתרי סופרמרקטים: הם מפתחים את כל הלוגיקה, והכל עובד נהדר על המחשב שלהם. אבל כשהם מריצים את זה על שרת, הם מקבלים נתונים חלקיים, מחירים לא נכונים, או הודעות "המוצר אינו זמין". הבעיה? הם נפלו במלכודת בחירת הסניף.

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

הפתרון דורש עבודה נוספת. ראשית, צריך למפות את כל הסניפים הזמינים. לרוב ניתן למצוא אותם בקריאת API ייעודית או בדף איתור סניפים. שנית, הלוגיקה של ה-scraper חייבת לבצע איטרציה: עבור כל סניף שמעניין אתכם, צריך להתחיל session חדש, לנווט לאתר, להגדיר את הסניף הרלוונטי (בדרך כלל דרך לחיצה על כפתור והגדרת cookie או ערך ב-localStorage), ורק אז להתחיל לאסוף את נתוני המוצרים. זה מאט את התהליך, אבל זה ההבדל בין דאטה חסר ערך לדאטה מדויק ואמין שאפשר לקבל עליו החלטות עסקיות. זו דוגמה קלאסית למורכבות הנסתרת בפרויקטים של מודיעין מתחרים שופרסל.

מתי לא להשתמש בדפדפן מלא: המקרה של ה-API הציבורי (הנסתר)

אחרי כל מה שאמרתי על חשיבות השימוש בדפדפן מלא, יש יוצא מן הכלל. לפעמים, אם יש לכם מזל, תוכלו למצוא endpoints של API שהם פחות מאובטחים ואינם דורשים session מורכב. זה לא ה-API הפנימי של האפליקציה, אלא למשל API שנועד להזין את מפת האתר (sitemap.xml) או אפליקציית מובייל ישנה. זה דורש עבודת בילוש.

פתחו את כלי המפתחים בדפדפן, סננו את תעבורת הרשת (XHR/Fetch) וחפשו קריאות שנראות פשוטות יחסית. חפשו endpoints שמחזירים JSON או XML עם רשימות מוצרים או קטגוריות. לפעמים, אפשר לשחזר את הקריאות האלה עם סקריפט פשוט המבוסס requests, אולי עם header בודד של Authorization או x-api-key שניתן לחלץ מהקוד. אם מצאתם נתיב כזה, הרווחתם. קריאות API ישירות מהירות בסדר גודל יותר מרינדור דף שלם ב-Playwright. Latency יכול לרדת מ-5-10 שניות לדף לפחות מ-500 מילישניות לבקשה.

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