למה `requests` לא יספיק לכם ב-ROL
בואו נשים את זה על השולחן: אם הגישה הראשונית שלכם ל-scraping ROL היא ספריית requests בפייתון, אתם בדרך לכישלון. הדף הראשוני שחוזר מהשרת הוא שלד HTML ריק כמעט לחלוטין. כל התוכן המעניין – רשימות מסעדות, תפריטים, מחירים וזמינות – נטען דינמית באמצעות קריאות JavaScript א-סינכרוניות. ניסיון לנתח את ה-HTML הסטטי יחזיר לכם דף ריק.
הפתרון היחיד הוא שימוש ב-headless browser. אני ממליץ על Playwright. הוא מהיר יותר, מודרני יותר, וה-API שלו נקי ואינטואיטיבי בהשוואה לכלים ישנים. המטרה הראשונית שלכם צריכה להיות לא לחלץ סלקטורים, אלא לפתוח את ה-DevTools, לעבור ללשונית Network ולצפות בתעבורת ה-XHR/Fetch. שם נמצא הזהב. רוב הסיכויים שתמצאו קריאות API פנימיות שמחזירות JSON נקי. ניתוח ה-JSON הזה הוא פי 10 יותר יציב ואמין מניתוח DOM שמשתנה כל הזמן.
השלב הראשון בפרויקט איסוף קטלוג ROL הוא מיפוי ה-endpoints האלה. תצטרכו להבין איך ה-pagination עובד ברמת ה-API ואיך בקשה לדף קטגוריה מתורגמת לקריאה עם פרמטרים כמו offset ו-limit. רק אחרי שתבינו את זרימת הדאטה הזו, תוכלו לבנות scraper יעיל שלא מבזבז משאבים על רינדור מלא של כל דף ודף.
ארכיטקטורת איסוף לניטור מחירים וזמינות
אחרי שמיפיתם את המבנה, השלב הבא הוא בניית מערך איסוף שיכול לפעול בסקייל. כשמדובר על ניטור מחירים ROL או מעקב מלאי/זמינות ROL, אנחנו מדברים על דרישות קרובות לזמן אמת. מסעדה יכולה לעדכן מחיר או להפוך מנה ללא זמינה בכל רגע. איסוף פעם ביום פשוט לא רלוונטי כאן.
זה אומר שאתם צריכים מערך פרוקסים חזק. אל תחשבו אפילו על proxies של דאטה סנטר; הם ייחסמו תוך שעות. אתם צריכים רשת של פרוקסי residential איכותיים עם יכולת rotation אוטומטית. כדי לעקוב אחרי 500 מסעדות מרכזיות כל 20 דקות, אתם מסתכלים על 1,500 בקשות בשעה רק כדי לבדוק סטטוס בסיסי. כל בקשה צריכה לצאת מ-IP אחר, עם user-agent מתאים ועם טביעת אצבע דפדפן (fingerprint) אמינה. אם אחוז ההצלחה שלכם יורד מתחת ל-98%, זה סימן שמנגנון ההגנה של האתר מזהה אתכם. המטרה היא לחלץ שני שדות קריטיים באופן עקבי: מחירים ו-זמינות. כל כישלון בחילוץ שלהם פוגע באיכות הדאטה.
בנוסף, תכננו את הלוגיקה שלכם להתמודדות עם שגיאות. מה קורה כשה-scraper נתקל בדף 404 כי מסעדה נסגרה? מה עושים עם שגיאת 503 זמנית? מערכת טובה לא נופלת, היא מסמנת את הבקשה ל-retry עם backoff אקספוננציאלי דרך תור משימות כמו RabbitMQ או Redis.
תרחיש הכישלון הנפוץ: הזמינות המדומה
הנה תרחיש שראיתי קורה יותר מדי פעמים בפרויקטים דומים: ה-scraper עובד, הוא מביא מחירים, הכל נראה ירוק. אבל הדאטה לא שווה כלום. למה? כי הוא לא מטפל נכון בפרמטר קריטי: המיקום הגיאוגרפי של המשתמש. אתר ROL, כמו כל פלטפורמת משלוחים, מציג זמינות ומחירים שונים בהתאם לכתובת שממנה הלקוח מזמין. אם תשלחו בקשות בלי קונטקסט גיאוגרפי (למשל, דרך פרוקסי בארה"ב), תקבלו נתונים לא רלוונטיים, או גרוע מזה, הודעה שכל המסעדות "לא זמינות כרגע באזורך".
הטעות היא להניח שהאתר מגיב אותו דבר לכל בקשה. הפתרון הוא לדמות משתמש אמיתי עד הסוף. זה אומר להשתמש בפרוקסי ישראליים בלבד, ולנהל סשנים עם cookies. לפני שאתם מתחילים לאסוף תפריטים, הבקשה הראשונה שלכם בסשן צריכה להיות הגדרת כתובת משלוח ספציפית בתל אביב, חיפה או ירושלים. רק אחרי שהאתר "יודע" איפה אתם, המידע שיוצג יהיה מדויק. ניהול הסשנים האלה מורכב, במיוחד כשמריצים מאות בקשות במקביל. צריך לוודא שכל סשן שומר על ה-cookies וה-LocalStorage שלו, ושהוא משויך לאותו IP לאורך זמן קצר. אם לא תעשו את זה, אתם פשוט אוספים זבל.
מאיסוף נתונים ל-API: הפיכת המידע למוצר
איסוף הדאטה הוא רק חצי מהעבודה. דאטה גולמי שיושב ב-CSV ב-S3 הוא טוב למ分析 разовый, אבל הערך האמיתי מגיע כשיוצרים ממנו מוצר. המטרה הסופית של רוב הפרויקטים האלה היא API / קובץ נתונים שהלקוח הפנימי או החיצוני יכול לצרוך.
זה אומר שאתם צריכים לבנות שכבת עיבוד ותקינות נתונים. ה-scraper שלכם צריך לדחוף את המידע הגולמי למסד נתונים (למשל, PostgreSQL), ושם ירוצו תהליכי ETL. התהליכים האלה יבצעו נורמליזציה של שמות (למשל, "פיצה מרגריטה" ו-"מרגריטה פיצה" יהפכו לאותו פריט), יזהו שינויי מחיר ויתייגו אותם, ויחשבו סטטיסטיקות. רק אחרי שהדאטה עבר ניקוי ואימות, הוא נחשף דרך API.
ה-API צריך להיות מתוכנן לפי ה-use cases. למשל, endpoint אחד עבור מודיעין מתחרים ROL, שיציג השוואת מחירים של פריטים ספציפיים בין מסעדות. endpoint אחר שיאפשר למשתמש לקבל את כל התפריט של מסעדה נתונה בפורמט JSON סטנדרטי. חשוב מאוד לנטר את ה-latency: קריאת API שמחזירה תפריט צריכה לקחת פחות מ-200ms. אם זה לוקח יותר, אתם צריכים לבדוק את האינדקסים במסד הנתונים או להוסיף שכבת caching עם Redis. הדאטה הגולמי הוא חומר הגלם, ה-API הוא המוצר המוגמר.
מתי לא כדאי לבנות Scraper כזה בעצמכם
אחרי כל מה שתיארתי, חייבים להיות כנים. לא תמיד בנייה של מערכת כזו in-house היא ההחלטה הנכונה. יש פרויקטים שבהם המורכבות והתחזוקה השוטפת פשוט לא מצדיקות את המאמץ. אם הצורך שלכם הוא נקודתי וחד-פעמי, למשל, איסוף קטלוג ראשוני של 100 מסעדות לצורך מחקר שוק, בניית מערך שלם עם Playwright, proxies ו-ETL היא over-engineering.
במצב כזה, פתרון ידני או חצי-אוטומטי עשוי להיות יעיל יותר מבחינת זמן ומשאבים. כמו כן, אם אין לכם בצוות מישהו עם ניסיון ספציפי ב-scraping וב-DevOps, אתם תתקלו בקשיים. תחזוקת מערכת כזו היא משרה בפני עצמה. מנגנוני ההגנה של אתרים כמו ROL משתנים. סלקטורים נשברים. מבנה ה-API הפנימי יכול להשתנות ללא הודעה מוקדמת. מישהו צריך להיות זמין לתקן את ה-scraper כשהוא נשבר, וזה תמיד קורה ברגע הכי לא צפוי.
הבנייה העצמית נכונה כשאיסוף הדאטה מ-ROL הוא ליבת העסק שלכם, כשאתם צריכים גמישות מלאה, וכשיש לכם את המשאבים והידע לתחזק את המערכת לטווח ארוך. בכל מקרה אחר, כדאי לשקול גישות חלופיות לאיסוף נתונים לפני שקופצים למים העמוקים של פרויקט פיתוח מלא.
