למה Requests פשוט לא יספיק לאתר כמו כאן

הטעות הראשונה שרוב המפתחים עושים היא להתייחס ל-כאן כמו לאתר סטטי. הם שולחים בקשת GET, מריצים BeautifulSoup על ה-HTML, ותוהים לאן נעלם כל התוכן. האמת היא ש-kan.org.il הוא יישום צד-לקוח מורכב. כשאתה נכנס לדף קטגוריה, הדפדפן שלך מריץ JavaScript שמבצע סדרת קריאות Fetch/XHR לרשת הפנימית של האתר כדי למשוך את רשימת התוכניות כ-JSON. ה-HTML הוא רק קונטיינר ריק.

הגישה הנכונה, אם כן, היא לא לנסות לרנדר את הדף, אלא לחקות את הדפדפן. פתחו את ה-Developer Tools (F12), עברו ללשונית Network, וסננו לפי XHR. נווטו באתר ותראו את בקשות ה-API שהדפדפן שולח. אלו מכרות הזהב שלכם. תמצאו שם endpoints שמחזירים רשימות תוכניות, פרטי פרקים, וכל המטא-דאטה שאתם צריכים. המשימה המרכזית עבור איסוף קטלוג כאן היא מיפוי ה-API הפנימי הזה. במקום לפרסר HTML שביר, אתם עובדים ישירות עם הנתונים המובנים. תוכלו לחלץ בקלות שדות כמו שמות מוצרים/מודעות (שמות התוכניות) וקטגוריות ללא מאמץ, עם 100% דיוק. זה דורש יותר עבודת בילוש בהתחלה, אבל התחזוקה לאורך זמן פשוטה פי עשרה.

ארכיטקטורת ה-Scraper: מעקב אחר תוכן דינמי

אחרי שמיפיתם את ה-API, השלב הבא הוא לבנות תהליך אוטומטי. זה קריטי עבור Use Cases כמו מעקב מלאי/זמינות כאן, שבעולם המדיה מתורגם למעקב אחר פרקים חדשים או תכנים שיורדים מהאוויר. המטרה היא לא לסרוק את כל האתר מחדש כל יום. זה לא יעיל ומעמיס על השרתים שלהם שלא לצורך.

הארכיטקטורה שאני מעדיף מבוססת על ניהול מצב. השתמשו במסד נתונים פשוט, אפילו SQLite יספיק לפרויקטים קטנים, כדי לשמור מזהה ייחודי (ID) של כל פרק או תוכנית שכבר סרקתם. התהליך היומי שלכם ייראה כך: קודם כל, הוא יסרוק את עמודי הקטגוריות הראשיים או את ה-endpoint של "נוספו לאחרונה". עבור כל פריט שמתקבל, הוא יבדוק אם המזהה שלו כבר קיים במסד הנתונים. אם לא, זהו תוכן חדש. רק אז הוא ימשיך לסרוק את עמוד הפרטים המלא שלו, יוסיף את המידע למאגר שלכם, ויסמן את המזהה כ"נצפה". גישה זו מפחיתה את מספר הבקשות ב-95% לאחר הסריקה הראשונית. אנחנו מדברים על קטלוג של כ-10,000 פריטי VOD; סריקה מלאה יכולה לקחת 20-30 דקות, אבל סריקה יומית של שינויים בלבד צריכה להסתיים תוך פחות מ-2 דקות. שמרו על קצב בקשות מתון של 5-10 בקשות לדקה, זה מספיק בהחלט.

תרחיש הכשל הנפוץ: Geoblocking ו-CDN

כאן מגיע הקיר שרבים נתקעים בו. אתם בונים scraper מושלם על המחשב המקומי שלכם, הכל עובד. אתם מעלים אותו לשרת ב-AWS ב-us-east-1 ומריצים. פתאום, כל הבקשות שלכם לתוכן ספציפי מתחילות להחזיר 403 Forbidden או הודעת שגיאה על כך שהתוכן אינו זמין באזורכם. זהו Geoblocking קלאסי. תאגיד השידור הציבורי, כמו גופי שידור אחרים, מחויב להגביל חלק מהתכנים שלו לטריטוריית ישראל בלבד בגלל זכויות יוצרים.

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

לא תמיד צריך Headless Browser, אבל כדאי להיות מוכנים

זו הנקודה שבה אני חלוק עם חלק מהקולגות. הגישה המועדפת שלי היא תמיד להתחיל עם ניתוח ה-API הפנימי. היא מהירה יותר, זולה יותר לביצוע, וצריכת המשאבים שלה נמוכה בסדרי גודל. אבל מה קורה כשה-API הזה מוגן במנגנונים מתוחכמים? לפעמים, כדי לקבל טוקן גישה תקף, צריך לפתור אתגר JavaScript שרץ בדפדפן. במקרים כאלה, ניסיון לשחזר את הלוגיקה ב-Python הוא קרב אבוד מראש.

כאן נכנסים לתמונה כלים כמו Playwright או Puppeteer. הם מריצים מופע אמיתי של דפדפן, כך שכל ה-JavaScript של האתר רץ באופן טבעי. אם אתם נתקלים בחסימה שקשה לפענח, זו תוכנית המגירה שלכם. עם זאת, אל תקפצו ישר לפתרון הזה. הרצת דפדפן מלא עבור כל בקשה היא בזבוז משאבים עצום. ה-latency קופץ מ-200ms לכ-3-5 שניות לבקשה, וצריכת הזיכרון מזנקת. לכן, אני ממליץ על גישה היברידית: השתמשו ב-Playwright פעם אחת כדי לטעון את הדף, לחלץ את הטוקנים או העוגיות הנדרשות, ואז השתמשו בהם כדי לשלוח את כל שאר בקשות ה-API עם ספרייה קלת משקל כמו httpx. זה נותן לכם את הטוב משני העולמות. למידע נוסף על הסוואת הבוט שלכם, קראו על טכניקות ב-Playwright stealth.

בניית API וייצוא נתונים מתוכן שגירדתם

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

השלב הראשון הוא נורמליזציה. ה-API הפנימי של כאן עשוי להשתנות בין endpoints שונים. תפקיד ה-scraper הוא ליצור סכמה אחידה. לדוגמה, שדה programTitle ב-endpoint אחד ו-seriesName באחר צריכים להפוך לשדה title אחיד במסד הנתונים שלכם. השלב הבא הוא החצנת הנתונים. שתי הדרכים הנפוצות ביותר הן:

  1. ייצוא יומי: תהליך שרץ פעם ביום, לוקח את כל הנתונים החדשים מה-24 שעות האחרונות ומייצא אותם לקובץ CSV או JSON Lines. קובץ כזה, המכיל כמה מאות עדכונים, יהיה קטן (פחות מ-5MB) וקל לעיבוד על ידי מערכות אחרות.
  2. בניית API: הקמת שרת API פשוט (למשל עם FastAPI) שחושף את הנתונים שאספתם. זה מאפשר למערכות אחרות לשאול שאלות ספציפיות כמו "הבא לי את כל הפרקים החדשים של סדרה X" בזמן אמת. ניהול נכון של שגיאות, כמו טיפול בשגיאות 429 מהצד שלכם, הוא קריטי כדי לספק שירות אמין למשתמשי ה-API שלכם.