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

בואו נניח את זה על השולחן: אם אתם מנסים לגשת לדף מוצר ב'עברית' עם קריאת GET פשוטה, תקבלו HTML בסיסי, אבל כנראה שלא את כל המידע שאתם צריכים. הפרטים החשובים באמת, כמו מחיר עדכני, מבצעים, ובעיקר זמינות, נטענים אסינכרונית באמצעות JavaScript לאחר שהדף הראשוני כבר נטען בדפדפן. זו טכניקה נפוצה באתרי e-commerce מודרניים, והיא המכשול הראשון והמשמעותי ביותר.

ניסיון לחלץ מחירים באמצעות סלקטורים של CSS או XPath על ה-HTML הגולמי יחזיר לכם ערכים ריקים או, במקרה הגרוע יותר, מידע לא עדכני. זה קריטי במיוחד עבור use case כמו ניטור מחירים בעברית, שם דיוק של דקות יכול להיות ההבדל בין תובנה שווה למספר חסר משמעות. הפתרון הוא לא לנסות לפענח את קריאות ה-API הפנימיות שלהם. זה אולי יעבוד לשבוע, אבל בשינוי ה-endpoint הבא, כל המערכת שלכם תקרוס. הגישה היציבה היא להשתמש ב-headless browser שמריץ את ה-JavaScript בדיוק כמו דפדפן אמיתי. תפסיקו עם Selenium לפרויקטים חדשים. המדריך המלא ל-Playwright stealth הוא נקודת הפתיחה שלכם. הוא מהיר יותר, יציב יותר, והקהילה סביבו פותרת בעיות בקצב גבוה בהרבה.

בניית מפת אתר אפקטיבית לקטלוג המלא

אוקיי, אז החלטנו להשתמש ב-Playwright. עכשיו איך מוצאים את כל הספרים? איסוף קטלוג עברית הוא אתגר בפני עצמו. אין פה קובץ sitemap.xml מסודר שיגיש לכם את כל 30,000+ כתובות ה-URL של המוצרים על מגש. תצטרכו לבנות זחלן (crawler) ייעודי.

הגישה הנכונה היא דו-שלבית. שלב א': זחילת עומק. התחילו מעמוד הבית, אספו את כל הקישורים לקטגוריות הראשיות והמשניות. לאחר מכן, עבור כל עמוד קטגוריה, תצטרכו לטפל בפאגינציה כדי לאסוף את הקישורים לכל עמודי המוצר. שימו לב: הפאגינציה יכולה להיות מבוססת פרמטר URL (?page=2) או טעינה דינמית עם גלילה (infinite scroll). תצטרכו לכתוב לוגיקה שתזהה ותטפל בשני המקרים. המטרה של השלב הזה היא אך ורק לייצר רשימה מלאה של כתובות URL של מוצרים ולשמור אותה במסד נתונים או בקובץ. אל תנסו לחלץ את פרטי המוצר בשלב הזה – זה מפריד בין הדאגות (separation of concerns) ושומר על התהליך נקי.

שלב ב': חילוץ ממוקד. עכשיו, עם רשימת ה-URLs המוכנה, אתם יכולים להריץ את ה-scraper הכבד יותר (זה שמשתמש ב-Playwright) במקביל על מספר תהליכים או מכונות. גישה זו מאפשרת לכם לנהל כישלונות בצורה מבודדת. אם scraper אחד נכשל על מוצר ספציפי, הוא לא עוצר את כל תהליך איסוף הקישורים.

התמודדות עם חסימות: פרוקסי וניהול טביעות אצבע

ברגע שתתחילו לשלוח בקשות בקצב גבוה, אפילו עם Playwright, תתקלו בחסימות. אתר כמו 'עברית' משתמש במערכות הגנה כדי למנוע עומס מבוטים. שליחת 500 בקשות בדקה מאותה כתובת IP היא דגל אדום בוהק. זה לא עניין של אם, אלא של מתי תקבלו שגיאות 403 או CAPTCHA.

הפתרון הוא rotation של פרוקסי. אבל לא כל פרוקסי יתאים. פרוקסים של דאטה סנטר הם זולים ומהירים, אבל קל מאוד לזהות ולחסום אותם. עבור אתר כזה, אתם צריכים להשקיע בגישה מתוחכמת יותר. איך לבחור פרוקסי residential איכותי מסביר את ההבדלים לעומק, אבל הנקודה המרכזית היא שכתובות IP ביתיות נראות כמו תנועה של משתמשים אמיתיים ומורידות את הסיכוי לחסימה באופן דרמטי. שלבו את זה עם ניהול טביעת אצבע (fingerprint) של הדפדפן. זה כולל User-Agent אקראי (אבל הגיוני), שינוי רזולוציית מסך ופרמטרים אחרים שספריות כמו puppeteer-extra-plugin-stealth (שעובדת גם עם Playwright) עושות אוטומטית. המטרה היא שכל בקשה תיראה כאילו היא מגיעה ממשתמש אחר, במקום אחר, במכשיר אחר.

תרחיש הכשל הנפוץ ביותר: שינויים במבנה ה-DOM

בניתם הכל. הפרוקסי עובד, ה-scraper רץ, ואתם אוספים נתונים בהצלחה של 99.8%. אתם הולכים לישון מרוצים. בבוקר אתם קמים ל-15,000 שורות ריקות במסד הנתונים. מה קרה? ברוכים הבאים לבעיית התחזוקה מספר אחת ב-web scraping: שינויים ב-frontend.

מפתחי האתר של 'עברית' שינו שם של class באלמנט שמכיל את המחיר. זה הכל. שינוי קטן, אולי מ-"price-final" ל-"final-price-tag", והסלקטור שלכם נשבר. ה-scraper לא נכשל עם שגיאה, הוא פשוט לא מוצא את האלמנט ומחזיר null. זהו כישלון שקט ומסוכן. כדי להתמודד עם זה, חייבים לבנות מערכת ניטור ובדיקות. אחרי כל ריצה, בדקו באופן אוטומטי ששדות חיוניים (כמו מחיר ושם מוצר) לא ריקים ביותר מ-5% מהמקרים. אם כן, שלחו התראה מיידית. בנוסף, אל תסתמכו על סלקטורים שבירים מדי. במקום לנבור שלוש רמות של div-ים, חפשו אלמנט עם data-testid="product-price" אם קיים. סלקטורים כאלה נוטים להיות יציבים יותר כי הם משמשים לבדיקות E2E של המפתחים עצמם. אם אין כאלה, בנו סלקטורים גמישים יותר שמסתמכים פחות על מבנה ה-HTML המדויק ויותר על יחסים בין אלמנטים.

מאיסוף נקודתי ל-API נתונים שמיש

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

הגדירו סכמה ברורה. כל רשומה של ספר צריכה להכיל שדות קבועים: מזהה ייחודי (ISBN הוא אידיאלי), שם, מחבר, מחיר, זמינות, קטגוריה, ותאריך איסוף הנתונים (timestamp). נרמלו את הנתונים תוך כדי חילוץ. הסירו רווחים מיותרים, הפכו מחירים למספרים (float), והמירו תאריכים לפורמט ISO 8601. הנתונים הנקיים האלה צריכים להישמר במסד נתונים מבני כמו PostgreSQL, לא בקבצים שטוחים. משם, בניית API פשוט מעל מסד הנתונים היא משימה קלה יחסית עם כלים כמו FastAPI או Express. זה מאפשר לצרכני המידע שלכם לקבל נתונים עדכניים on-demand, במקום לחכות לייצוא ידני. אם אתם נתקלים בחסימות תכופות, חשוב שתבינו איך לטפל בהן נכון. הבנת שגיאות 429 ו-rate limiting היא קריאת חובה לכל מי שבונה מערכת איסוף נתונים אמינה.