Extract + Load — requests ו-to_sql
מה זה?
עד עכשיו טענו נתונים מקבצים סטטיים (read_csv). אבל ETL אמיתי (Extract-Transform-Load) שולף נתונים ממקורות חיים — API חיצוני, מסד נתונים — מעבד אותם (כל מה שלמדנו עד כה), וכותב את התוצאה בחזרה למקום קבוע. requests הוא ה-Extract מ-API; to_sql הוא ה-Load למסד נתונים — שני הקצוות של כל צנרת ETL.
מילות מפתח שחשוב לזכור
• Extract — שליפת נתונים גולמיים ממקור חיצוני (API, קובץ, DB)
• Transform — עיבוד וניקוי הנתונים (כל מה שנלמד בשיעורים הקודמים ביחידה)
• Load — כתיבת התוצאה הסופית ליעד קבוע (DB, קובץ)
• requests — ספריית Python לביצוע קריאות HTTP (מקביל ל-HttpClient ב-C#)
• to_sql() — כותב DataFrame ישירות לטבלת SQL, בלי לבנות שאילתת INSERT ידנית
import requests
import pandas as pd
# Extract — fetching from an external API, just like HTTP GET from the ASP.NET Core unit
response = requests.get("https://api.example.com/orders")
data = response.json() # decode JSON into a list of dicts
df = pd.DataFrame(data) # direct conversion to a DataFrame
# Extract from an existing database
import sqlalchemy
engine = sqlalchemy.create_engine("postgresql://user:pass@localhost/mydb")
df_from_db = pd.read_sql("SELECT * FROM orders WHERE status = 'completed'", engine)# Transform — everything already learned in this unit
df["OrderDate"] = pd.to_datetime(df["OrderDate"])
df_clean = df.dropna(subset=["CustomerId"])
summary = df_clean.groupby("CustomerId").agg(Total=("Amount", "sum")).reset_index()# Load — writing back to the database
summary.to_sql("customer_summary", engine, if_exists="replace", index=False)
# creates/replaces the customer_summary table with the processed result — no manual SQL INSERTהסבר עיקרי
requests.get מקביל ל-HttpClient ב-C#, אבל בלי async מפורש — קריאת HTTP בפייתון עם requests דומה מאוד לרעיון שכבר מוכר מיחידת ASP.NET Core (בקשה, תשובה, .json() לפענוח) — רק שהתחביר הבסיסי (לא-async כברירת מחדל) פשוט יותר, מתאים לסקריפטים חד-פעמיים/מתוזמנים בניגוד לשרת שמשרת הרבה בקשות במקביל.
to_sql הוא Load אמיתי, לא רק “שמירת קובץ” — בניגוד ל-to_csv (כתיבה לקובץ, פשוטה יותר), to_sql כותב ישירות לטבלת DB אמיתית — שימושי כשתוצאת העיבוד צריכה “לחיות” במסד נתונים production, נגישה לשירותים אחרים (כמו ה-API ב-C# מיחידות קודמות) לא רק כקובץ מקומי.
if_exists="replace" הוא החלטה חשובה — כשה-Load רץ שוב (למשל בהרצה מתוזמנת יומית, נושא השיעור הבא), האם התוצאה החדשה מחליפה את הישנה ("replace"), מתווספת אליה ("append"), או שהריצה נכשלת אם הטבלה כבר קיימת ("fail", ברירת המחדל)? הבחירה תלויה בטבע הנתונים — דוח יומי-מצטבר לרוב “replace” (הדוח החדש מייצג את כל התמונה), לוג אירועים לרוב “append” (מוסיפים לרשומה קיימת).
יתרונות
requests נותן גישה פשוטה למקורות נתונים חיים (APIs), לא רק קבצים סטטיים; to_sql כותב תוצאות ישירות ל-DB בלי SQL ידני; שילוב Extract→Transform→Load בסקריפט אחד ממחיש את כל מחזור החיים של הנתונים.
חסרונות
requests.get בלי טיפול שגיאות (timeout, סטטוס לא-2xx) עלול לקרוס בשקט על בעיות רשת; to_sql על DataFrame ענק עלול להיות איטי בהשוואה לכלי Bulk Insert ייעודיים.
נקודות חשובות
• Extract-Transform-Load: שליפה ממקור, עיבוד, כתיבה ליעד — סדר תמידי
• requests.get(url).json() שולף ומפענח מ-API; pd.read_sql שולף מ-DB קיים
• to_sql כותב DataFrame ישירות לטבלה, עם if_exists (replace/append/fail) קובע התנהגות בהרצה חוזרת
• Extract/Load הם שני הקצוות; Transform הוא כל מה שכבר נלמד קודם ביחידה
טעויות נפוצות
• לא לבדוק response.status_code לפני .json() — קריסה לא-ברורה אם ה-API החזיר שגיאה
• לבחור if_exists="fail" (ברירת מחדל) בטעות בהרצה חוזרת ולקבל שגיאה במקום עדכון מצופה
• לשכוח שה-Transform (ניקוי, סינון) צריך לקרות לפני ה-Load, לא אחריו
סיכום
ETL הוא Extract (שליפה ממקור — API עם requests, או DB עם read_sql), Transform (עיבוד — כל מה שנלמד קודם ביחידה: merge/groupby/ניקוי), ו-Load (כתיבה ליעד — to_sql ל-DB). if_exists קובע איך הLoad מתנהג בהרצות חוזרות — replace/append/fail, החלטה שתלויה בטבע הדוח. זהו המסגרת המלאה שהפרויקט המסכם של היחידה יבנה עליה.
דוקומנטציה רשמית
תרגילים
תרגיל 1 — Extract מ-API
המשימה: בחרו API ציבורי חינמי (למשל JSONPlaceholder), שלפו נתונים עם requests.get, והמירו ל-DataFrame.
בדיקה: ה-DataFrame מכיל את הנתונים מה-API, עם עמודות תואמות למבנה ה-JSON שהתקבל.
תרגיל 2 — Load ל-SQL
המשימה: קחו DataFrame מעובד (מתרגיל קודם ביחידה) וכתבו אותו לטבלת SQLite/Postgres מקומית עם to_sql.
בדיקה: שאילתה ישירה על הטבלה (SELECT * FROM ...) מציגה את הנתונים שנכתבו.
פרויקט מסכם
המשימה: בנו סקריפט ETL מלא: Extract מ-API ציבורי → Transform (ניקוי + groupby) → Load ל-DB מקומי.
דרישות:
- Extract עם
requests, כולל בדיקתstatus_codeלפני עיבוד - Transform: ניקוי (
fillna/dropnaלפי הצורך) וקיבוץ (groupby+agg) לסיכום משמעותי - Load עם
to_sql, ובחירה מנומקת שלif_exists(replaceאוappend) לפי טבע הנתונים
בדיקה: הרצת הסקריפט מקצה לקצה מייצרת טבלה ב-DB עם נתונים מעובדים ונכונים; הרצה חוזרת מתנהגת כצפוי לפי if_exists שנבחר.
מה בפרק הבא
בפרק הבא — Scheduling ולוגים: איך מריצים את סקריפט ה-ETL אוטומטית מדי יום (cron/APScheduler), עם לוגים מובנים שמתעדים מה קרה בכל הרצה.