למה Requests ו-BeautifulSoup לא יספיקו לכם כאן

אני רואה את זה קורה כל הזמן. מהנדס מנסה לגשת לאתר כמו Ontopo, מריץ בקשת GET פשוטה ומקבל בחזרה HTML ריק או שלד של אפליקציה בלי שום דאטה. למה? כי רוב האתר הוא Single-Page Application (SPA). הדפדפן טוען קובץ JavaScript גדול, והוא זה שאחראי לרנדר את הממשק ולשלוף את הנתונים מ-API פנימי.

ניסיון לעשות reverse engineering ל-API הפנימי שלהם הוא מסלול שמוביל לתסכול. ה-endpoints האלה מוגנים. הם דורשים headers ספציפיים, טוקנים של סשן (session tokens), ולפעמים גם CSRF tokens שנוצרים ומתעדכנים על ידי קוד שרץ בצד הלקוח. כל שינוי קטן ב-build של האתר יכול לשבור לך את כל הלוגיקה. זה משחק של חתול ועכבר שאתה תפסיד בו בטווח הארוך. הזמן שתשקיע בדיבוג הרשת שלהם יתבזבז ברגע שהם יעשו את ה-deploy הבא.

לכן, נקודת הפתיחה לפרויקט scraping Ontopo רציני היא דפדפן headless. תפסיקו עם Selenium לפרויקטים חדשים. Playwright מנצח אותו ב-2025 בכל מטריקה רלוונטית — מהירות, יציבות, וה-API שלו פשוט נקי יותר. שימוש ב-Playwright עם תוספים כמו playwright-stealth הוא לא המלצה, הוא דרישת בסיס כדי לעבור את ההגנות הראשוניות ולהיראות כמו משתמש אמיתי.

בניית תהליך איסוף הקטלוג המלא

אחרי שהתמקמנו על Playwright, המשימה הראשונה היא איסוף קטלוג Ontopo המלא. מדובר על סריקה של כל המסעדות בפלטפורמה כדי לבנות בסיס נתונים ראשוני. התהליך מתחיל מעמוד החיפוש הראשי. שימו לב שהרשימה לא נטענת בבת אחת; היא משתמשת ב-infinite scroll. תצטרכו לכתוב לוגיקה שמגלגלת את העמוד למטה, ממתינה לטעינת התוכן החדש (locator.waitFor), וחוזר חלילה עד שלא מופיעות תוצאות חדשות. אל תשתמשו ב-sleep קבוע, זה לא יציב.

בסריקה הראשונית שלי זיהיתי כ-2,500 מסעדות פעילות. מכל עמוד מסעדה, המטרה היא לחלץ את הנתונים הסטטיים: שם, כתובת, קטגוריות (למשל, 'איטלקי', 'אסייתי'), שעות פתיחה, וקישור לתפריט. את המידע הזה כדאי לשמור במסד נתונים יציב. זה הבסיס שלכם. קצב סביר לאיסוף כזה, כדי לא לעורר חשד, הוא בקשה אחת כל 3-5 שניות פר IP. עם proxy rotation טוב, אפשר להקביל את התהליך ולהשלים את איסוף הקטלוג כולו תוך כמה שעות.

האתגר כאן הוא לא טכני במיוחד, אלא נוגע יותר לניקיון וסטרקטורה של הדאטה. ה-selectors של ה-CSS עלולים להיות לא יציבים. העדיפו תמיד להשתמש ב-data-attributes או סלקטורים מבוססי טקסט אם אפשר, הם נוטים להשתנות פחות מ-class names שנוצרים אוטומטית.

האתגר האמיתי: מעקב זמינות בזמן אמת

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

זה תהליך איטי ועדין. כל אינטראקציה כזו מייצרת קריאת API ברקע. אם תנסו לבדוק 20 תאריכים שונים ברצף מהיר מדי מאותו סשן דפדפן, אתם תקבלו חסימה זמנית ברמת הווידג'ט. ראיתי את זה קורה: אחרי 5-6 בקשות מהירות, לוח השנה פשוט מפסיק להגיב או מחזיר הודעת שגיאה. זהו failure scenario קלאסי באתרים כאלה. הפתרון הוא לעבוד לאט יותר, או להשתמש בסשנים נפרדים (והכרחי, פרוקסי residential שונים) עבור כל קבוצת בדיקות קטנה. עם ניהול סשנים ופרוקסי נכון, ניתן להגיע לאחוזי הצלחה של 98% באיסוף נתוני זמינות.

מתי Scraping ישיר הוא לא הפתרון הנכון

אני יודע מה אתם חושבים: למה לא פשוט למצוא את קריאת ה-API שמביאה את הזמינות ולשכפל אותה? זו גישה קוסמת, במיוחד אם המטרה היא רק ניטור מחירים Ontopo (במקרה הזה, מבצעים או תפריטים מיוחדים) על 10-15 מסעדות ספציפיות. במקרה כזה, לפעמים אפשר, עם מאמץ, לבודד את הבקשה, לשכפל את ה-headers וה-cookies, ולקבל את המידע בצורה יעילה בהרבה מאשר הרצת דפדפן מלא.

אבל כאן מגיע ה'אבל' הגדול. הגישה הזו שבירה להחריד. היא תלויה לחלוטין במימוש הנוכחי של ה-API הפנימי של Ontopo. ברגע שהם ישנו פרמטר, יוסיפו header חדש לאימות, או ישנו את מבנה התשובה — כל הסקריפט שלכם קורס. זה פתרון טקטי, לא אסטרטגי. הוא לא מתאים לפרויקטים שדורשים אמינות לאורך זמן, כמו בניית API / קובץ נתונים Ontopo עבור לקוחות או מערכות פנימיות. התחזוקה הופכת לסיוט, ואתם תמצאו את עצמכם רודפים אחרי הזנב של צוות הפיתוח של Ontopo. גישת הדפדפן המלא, למרות שהיא דורשת יותר משאבים, מבודדת אתכם מרוב השינויים האלה. כל עוד האתר עובד למשתמש אנושי, הסקרייפר שלכם ימשיך לעבוד. אם אתם בכל זאת הולכים על גישת ה-API, תהיו מוכנים לטפל בהרבה שגיאות בלתי צפויות, כולל שגיאות 429 ו-rate limiting.

מודיעין מתחרים והפקת נתונים בקנה מידה גדול

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

האתגר הטכני כאן עובר מאיסוף לעיבוד ואחסון. אנחנו מדברים על דאטה-סט שיכול להגיע בקלות לעשרות ג'יגה-בייטים אחרי כמה חודשי איסוף, במיוחד אם שומרים snapshots של זמינות. תכנון סכמת הנתונים מראש הוא קריטי. איך תאחסנו את המידע כך שיהיה קל לתשאל אותו? האם תשתמשו ב-PostgreSQL עם PostGIS לניתוחים גיאוגרפיים? או אולי מסד נתונים NoSQL כמו MongoDB שמתאים יותר למבנים דינמיים? התשובה תלויה בשאלות העסקיות שאתם רוצים לענות עליהן. השלב הסופי הוא בדרך כלל ייצוא CSV/API יומי או שבועי של התובנות האלה, כדי שמערכות אחרות יוכלו לצרוך אותן.