למה הכלים הרגילים שלכם יכשלו מול התקציב הפתוח
רובנו מגיעים לפרויקט חדש עם סט כלים מוכר. אבל להפעיל סקרייפר Playwright גנרי על אתר כמו 'התקציב הפתוח' זה כמו להביא טנק למרוץ פורמולה 1. כן, הוא יזוז, אבל הוא יפספס את כל המטרה. הבעיה כאן היא לא JavaScript rendering. האתר מציג נתונים דרך קריאות API ברורות למדי שמחזירות JSON. האתגר האמיתי הוא לא בגישה לדאטה, אלא בנפח ובמבנה שלו. אנחנו מדברים על היררכיות שיכולות להגיע לעומק של 7-10 רמות, עם אלפי סעיפים מקוננים. סקרייפר שרק מבצע 'איסוף קטלוג' על ידי מעבר רקורסיבי על ה-tree יכול בקלות להיכנס ללולאות או לפספס ענפים שלמים.
הגישה הנכונה דורשת חשיבה שונה. במקום להתמקד ב-headless browser, צריך להתמקד ב-client HTTP חכם כמו httpx עם תמיכה ב-async. המטרה היא לא לדמות משתמש, אלא לדבר ישירות עם ה-API שהאתר עצמו צורך. זה מאפשר לנו להגיע לקצב בקשות גבוה משמעותית ולשלוט בתהליך בצורה גרעינית. מצאנו שהגבלה לקצב של 15-20 בקשות בדקה מ-IP בודד מונעת שגיאות 503 זמניות שמופיעות תחת עומס גבוה יותר. זהו משחק של סבלנות ודיוק, לא של כוח גס. כל המאמץ צריך להיות מושקע במיפוי ה-endpoints של ה-API ובניית לוגיקה שמבינה את הקשרים בין קטגוריות שונות, ולא בטיפול בשגיאות 429 קלאסיות.
ארכיטקטורת איסוף נתונים: ממודל בקשה-תגובה לפייפליין מבוסס אירועים
בפרויקט scraping התקציב הפתוח, המודל הפשוט של שליחת בקשה, קבלת HTML/JSON ועיבודו נשבר מהר מאוד. הסיבה היא תלות בין חלקי המידע. כדי להבין סעיף תקציבי אחד, ייתכן שתצטרכו מידע היררכי משלושה endpoints שונים. אם תנסו לעשות זאת באופן סדרתי, תהליך איסוף מלא ייקח ימים. המעבר למודל אסינכרוני הוא הכרחי, אבל לא מספיק.
הארכיטקטורה שעבדה לנו הכי טוב מבוססת על תורים (Queues). יש לנו סקרייפר 'מגלה' (Discovery Scraper) שתפקידו היחיד הוא לסרוק את רמות התקציב העליונות ולדחוף משימות (למשל, 'אחזר את כל תתי-הסעיפים של משרד החינוך') לתור RabbitMQ. בצד השני, יש לנו מספר 'עובדים' (Workers) ששולפים משימות מהתור, מבצעים את קריאות ה-API הספציפיות, ומעבדים את הנתונים. גישה זו מאפשרת סקיילביליות אופקית. אם האיסוף איטי מדי, פשוט מוסיפים עוד workers. זה גם הופך את המערכת לעמידה יותר בפני תקלות. אם worker אחד נופל, המשימה חוזרת לתור ותטופל על ידי worker אחר. כך אנחנו משיגים לא רק מהירות, אלא גם אמינות, שהיא קריטית כשמדובר על בניית API / קובץ נתונים פנימי שארגונים אחרים סומכים עליו.
המלכודת השקטה: כש-200 OK הופך לאויב הגדול ביותר
ה-failure mode הכי מסוכן ב-scraping של אתרי דאטה כמו 'התקציב הפתוח' הוא לא קבלת סטטוס 403 או 500. אלו שגיאות קלות לזיהוי. הסכנה האמיתית היא לקבל 200 OK עם דאטה שבור. זה קורה לעתים קרובות יותר ממה שחושבים. למשל, עדכון בצד השרת שמשנה שם של שדה ב-JSON מ-'amount' ל-'total_amount'. הסקרייפר שלכם ימשיך לרוץ. הוא יקבל תגובות 200, לא ידווח על שום שגיאה, אבל בשקט יתחיל למלא את הדאטהבייס שלכם בערכי null בעמודת הסכום. עד שתגלו את זה, יכולים לעבור שבועות, והנזק לנתונים ההיסטוריים שלכם יהיה עצום.
כדי להילחם בזה, חייבים להטמיע Data Validation כחלק אינטגרלי מהפייפליין. אנחנו משתמשים בספריות כמו Pydantic כדי להגדיר סכמה קשיחה לכל פיסת מידע שאנחנו מצפים לקבל. כל תגובת API עוברת ולידציה מול הסכמה הזו לפני שהיא נשמרת. אם שדה חסר, אם טיפוס הנתונים השתנה (למשל, מספר שהפך למחרוזת), התהליך נכשל באופן רועש ומיידי עם התרעה. זה דורש יותר מאמץ בהתחלה, אבל המאמץ הזה חוסך שבועות של דיבאגינג וכאבי ראש בהמשך. הצלחה של 99.9% באימות סכמה חשובה יותר מ-99.9% הצלחה בבקשות HTTP.
מעבר לדאטה גולמי: יצירת ערך עסקי וניתוחים השוואתיים
איסוף הנתונים הוא רק השלב הראשון. הערך האמיתי מגיע מהיכולת להשתמש בהם. אחד ה-use cases המרכזיים הוא מודיעין מתחרים, או בהקשר הזה, ניתוח השוואתי בין שנים או סעיפים. לדוגמה, חוקר או אנליסט ירצה לראות איך תקציב סעיף מסוים השתנה לאורך חמש שנים. כדי לאפשר זאת, הדאטה הגולמי, שהוא לרוב היררכי ולא נוח לעבודה, חייב לעבור נורמליזציה. אנחנו שומרים 'תמונות מצב' (snapshots) של התקציב המלא בכל פעם שאנחנו מזהים שינוי משמעותי, ומעבדים את ה-JSON המקונן למבנה טבלאי שטוח ב-Parquet או ישירות ב-data warehouse כמו BigQuery.
תהליך זה מאפשר לבצע שאילתות SQL מורכבות בקלות. למשל, SELECT year, sum(amount) FROM budget_items WHERE category_path LIKE '%education.primary%' GROUP BY year. שאילתה כזו בלתי אפשרית על קובצי JSON גולמיים. הפיכת הדאטה הגולמי למוצר נתונים שמיש היא המטרה הסופית. זה כולל גם בניית ייצוא CSV/API יומי או שבועי עבור משתמשים פנימיים, מה שהופך את המידע לנגיש הרבה יותר מאשר האתר המקורי. מה שמתחיל כפרויקט scraping התקציב הפתוח הופך לתשתית דאטה קריטית עבור הארגון.
מתי לא כדאי לבנות סקרייפר ייעודי (כן, יש מקרים כאלה)
למרות כל מה שאמרתי, יש מצבים שבהם בניית מערכת scraping מורכבת עבור 'התקציב הפתוח' היא פשוט בזבוז משאבים. אם כל מה שאתם צריכים זה נתונים נקודתיים פעם ברבעון, או תמונת מצב כללית של סעיף אחד, אל תבנו פייפליין מבוסס תורים עם ולידציית סכמות. זה over-engineering. במקרים כאלה, פתרון ידני או סקריפט פשוט ב-Python עם requests יעשה את העבודה בפחות זמן ומאמץ. המורכבות שאני מתאר במאמר הזה מוצדקת רק כאשר אתם צריכים נתונים באופן רציף, אמין, ובסקייל. למשל, עבור ניטור שינויים תקציביים בזמן אמת, או עבור מעקב אחר עדכוני נתונים ברמה יומית.
השאלה שצריך לשאול היא לא 'האם אנחנו יכולים לבנות את זה?', אלא 'מה העלות האלטרנטיבית של לא לבנות את זה?'. אם נתונים לא מדויקים או חסרים יגרמו להחלטות שגויות, אז ההשקעה בתשתית אמינה היא קריטית. אבל אם הפרויקט הוא חד-פעמי והדרישה היא לאסוף מידע עבור דוח ספציפי, עדיף להשקיע את הזמן בניתוח הנתונים עצמם ולא בהנדסת מערכת איסוף. יש הבדל עצום בין פרויקט מחקר חד-פעמי לבין בניית מוצר נתונים. חשוב להבין לאיזו קטגוריה אתם שייכים לפני שכותבים את שורת הקוד הראשונה. לפעמים, מדריך Playwright stealth הוא כל מה שצריך למשימה קטנה, גם אם הוא לא הפתרון ה'נכון' לטווח הארוך.
