למה Nevo הוא לא עוד אתר רגיל

ההבדל המהותי בגישה ל-Nevo מתחיל בהבנת הנכס. הנכס הוא טקסט משפטי יקר ערך, לא תמונות מוצר. האתר מגן עליו בהתאם. בניגוד לאתרי קמעונאות שמרוויחים מתנועה, כאן תנועה אוטומטית היא בעיקר נטל. המבנה שלו מורכב יותר: היררכיות של פסיקה, חקיקה, מאמרים, וקשרים סמנטיים ביניהם. מדובר על קטלוג של מעל 2 מיליון מסמכים, ולפעמים הדרך להגיע למסמך ספציפי דורשת ניווט דרך מספר עמודים ששומרים על session state. כל ניסיון לבצע איסוף קטלוג נבו באמצעות בקשות HTTP ישירות וחסרות state יתקל בכישלון מהיר. השרת מצפה לראות התנהגות אנושית, כולל טעינת JavaScript ואינטראקציה עם ממשק החיפוש. כל קיצור דרך כאן הוא מתכון לחסימת IP. לכן, נקודת המוצא שלנו חייבת להיות הדמיית דפדפן מלאה. זה לא המקום לחסוך במשאבים.

ה-Stack הנכון: תשכחו מ-Requests + BeautifulSoup

תפסיקו עם Selenium לפרויקטים חדשים. Playwright מנצח אותו ב-2025 בכל מטריקה רלוונטית. עבור Nevo, זה לא מותרות, זו דרישה. אנחנו צריכים יכולת מלאה להריץ דפדפן אמיתי (headless, כמובן) ולנהל אותו בצורה אסינכרונית. השילוב של Playwright עם Python ו-asyncio מאפשר לנו לנהל מספר דפדפנים במקביל, מה שמוריד דרמטית את זמן הריצה הכולל. ה-scraper שלנו צריך להיות stateful. כלומר, הוא צריך לזכור את מסלול הניווט, לנהל קוקיז, ואולי אפילו Local Storage כדי לשמר את ה-session. ראיתי יותר מדי פרויקטים נכשלים כי הם התייחסו לכל בקשה כעצמאית. ב-Nevo, בקשה להורדת פסק דין תלויה בסדרת הבקשות שהובילה אליה. בנוסף, חשוב להשתמש בתוספים שמקשים על הזיהוי האוטומטי. מדריך Playwright stealth הוא קריאת חובה לפני שאתם כותבים את שורת הקוד הראשונה. זה יחסוך לכם שעות של תסכול בהמשך הדרך.

ניהול Proxies וחסימות: המשחק האמיתי מתחיל כאן

בואו נהיה ריאליים: אתם תיחסמו. השאלה היא לא אם, אלא מתי ואיך אתם מתאוששים. ה-IP של השרת שלכם יישרף אחרי כמה מאות בקשות, אולי פחות. הפתרון הוא proxy rotation, אבל לא כל proxy מתאים. Datacenter proxies הם זולים ומהירים, אבל קלים מאוד לזיהוי. עבור אתר כמו Nevo, צריך להשתמש ב-residential proxies. הם איטיים יותר ויש להם עלות תפעול גבוהה יותר מבחינת מורכבות, אבל הם הדרך היחידה לקבל אחוזי הצלחה של מעל 95% לאורך זמן. המטרה היא להגביל את קצב הבקשות ל-IP בודד, נניח לא יותר מ-30-40 בקשות בדקה, ולבצע רוטציה חכמה. כשאתם מקבלים שגיאת 429 או נתקלים ב-CAPTCHA, המערכת שלכם צריכה אוטומטית להחליף IP, לנקות את ה-session, ולנסות שוב אחרי דיליי אקספוננציאלי. אם אתם לא בטוחים מאיפה להתחיל, קראו את המדריך על איך לבחור פרוקסי residential כדי להבין את ה-trade-offs. בניית לוגיקת ה-retry הזאת היא מה שמבדיל בין scraper שמביא 1,000 מסמכים ונופל, לבין מערכת שמייצרת API / קובץ נתונים נבו באופן עקבי.

תרחיש כישלון קלאסי: הזנחת ה-Session State

ראיתי את זה קורה עשרות פעמים. מהנדס מקים scraper ל-Nevo, מצליח לחלץ נתונים מהעמוד הראשי ומרשימת התוצאות הראשונה. הכל נראה טוב. הוא מריץ את ה-scraper על כל הקטלוג, הולך לישון, וחוזר בבוקר ל-CSV ריק ויומן שגיאות מלא ב-HTTP 403 או דפים ריקים. מה קרה? ה-scraper שלו היה stateless. הוא ניגש ישירות ל-URL של עמוד 50 בתוצאות החיפוש, בלי לעבור קודם בעמוד החיפוש עצמו. השרת של Nevo, כמו כל מערכת מורכבת, מצפה לטוקן מסוים ב-session או בקוקי שנוצר רק לאחר ביצוע החיפוש. בלי הטוקן הזה, כל בקשה ישירה לדפים עמוקים נתפסת כפעילות של בוט ונחסמת מיד. זה כישלון שנובע מחשיבה במונחים של בקשות בודדות במקום זרימת משתמש שלמה. הפתרון הוא לתכנן את ה-scraper כ-state machine: כל worker מתחיל בעמוד הבית, מבצע חיפוש, מנווט בין דפי תוצאות, ורק אז ניגש לדפים הפנימיים. זה איטי יותר פר-בקשה, אבל אינסוף יותר יציב לאורך זמן.

מאיסוף גולמי לדאטה מובנה: Parsing וייצוא

הצלחתם להוריד את ה-HTML. עכשיו מתחילה העבודה האמיתית. המבנה של דפי פסיקה או חקיקה ב-Nevo הוא סמי-מובנה. יש שדות ברורים כמו שמות מוצרים/מודעות (במקרה שלנו, כותרות המסמכים) או קטגוריות (תחום משפטי), אבל גוף הטקסט עצמו דורש parsing מורכב יותר. חשוב לבנות parser חסין לשינויים קטנים ב-HTML. אל תסתמכו על x-path מלא ושביר. השתמשו בסלקטורים חכמים שמבוססים על data attributes או שילוב של class ו-id. המטרה היא לא רק לחלץ את הנתונים, אלא להפוך אותם לשימושיים. זה אומר לנקות את הטקסט, לתקן קידוד, ולהעשיר את המידע עם מטא-דאטה (למשל, תאריך האיסוף). התוצר הסופי צריך להיות ייצוא CSV/API יומי או שבועי שקל לצרוך. בין אם זה לטובת ניטור מחירים נבו (למשל, מעקב אחר שינויים בשכר טרחה מומלץ) או לטובת מודיעין מתחרים נבו, הדאטה חייב להיות נקי, עקבי, וזמין באופן אמין. פרויקטים רבים נתקעים בשלב הזה כי הם מזלזלים במורכבות של הפיכת HTML מבולגן לדאטה-סט מובנה. אל תהיו אחד מהם. אם אתם נתקלים ב-HTML מסובך במיוחד, יש טכניקות parsing מתקדמות ל-HTML מורכב שיכולות לעזור.

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

למרות כל מה שאמרתי, לא תמיד צריך להוציא את התותחים הכבדים. אם כל מה שאתם צריכים זה לעקוב אחרי 10-20 פסקי דין ספציפיים ולקבל התראה על עדכון פעם בחודש, הקמת מערך Playwright עם מאגר פרוקסיז היא בזבוז זמן ומאמץ. במקרה כזה, סקריפט פשוט שמבקר ישירות ב-URLs הידועים פעם ביום יכול להספיק. גם אם הוא ייכשל מדי פעם, ההשפעה תהיה מינורית. הגישה המורכבת שתיארתי מיועדת למקרים שבהם נדרש איסוף רחב היקף ועקבי. אם אתם בונים מוצר שמתבסס על הנתונים מ-Nevo, או שאתם צריכים לבצע מעקב מלאי/זמינות נבו על אלפי מסמכים חדשים מדי שבוע, אז אין ברירה. אבל למשימות קטנות וממוקדות, הפתרון הפשוט והשביר ביותר הוא לפעמים הפתרון הנכון. תמיד תשאלו את עצמכם מהי עלות הכישלון. אם כישלון חד פעמי הוא לא קריטי, לכו על הפתרון המהיר. אם יציבות ואמינות הן דרישות ליבה, תשקיעו ב-setup הנכון מההתחלה.