JSON וצריכת API בפייתון
JSON קיצור של JavaScript Object Notation הוא פורמט שבו משתמשים מחשבים לאחסון מידע ותקשורת. יתרונו הגדול בכך שכל שפות המחשב מסוגלות להשתמש בו. לפיכך, רוב ממשקי הנתונים - API - בימינו משתמשים בו. לדוגמה: מפות גוגל, אפליקציות של מזג אוויר, מערכות תשלומים והזמנות מקוונות.
במדריך נלמד איך להשתמש ב-JSON בפייתון. בסוף המדריך כללתי מיני-פרוייקט במסגרתו נוריד את התמונה היומית מה-API של סוכנות החלל האמריקאית, NASA. לדוגמה, התמונה הבאה שהופצה ביום כתיבת המדריך:
אבל קודם נלמד מה זה JSON מפני שזה הפורמט שבאמצעותו NASA, ורבים וטובים אחרים, מספקת את השירות.
מה זה JSON?
JSON קיצור של JavaScript Object Notation הוא פורמט שבו משתמשים מחשבים לאחסון מידע ותקשורת. יתרונו הגדול בכך שכל שפות המחשב מסוגלות להשתמש בו. לפיכך, רוב ממשקי הנתונים - API - בימינו משתמשים בו. לדוגמה: מפות גוגל, אפליקציות של מזג אוויר, מערכות תשלומים והזמנות מקוונות.
את ה- JSON מקיפים סוגריים מסולסלים:
{}
JSON עשוי משדות. כל שדה מורכב מצמדים של מפתחות וערכים key : value. לדוגמה:
{
"name": "BMW"
}
- בדוגמה, "name" הוא המפתח והערך הוא "BMW".
- בין המפתח לערך מפרידות נקודתיים.
שימו לב לתחביר:
א. את שמות השדות חייבים להקיף במרכאות כפולות
ב. את הערכים שהם מחרוזות גם כן צריך להקיף במרכאות
ג. את ערכי המספרים לא חייבים להקיף במרכאות
{
"name": "BMW",
"price": 24000
}
ד. את הסוגים הבוליאניים (true, false) צריך לכתוב באותיות קטנות בלבד ואין להקיף במרכאות:
{
"name": "BMW",
"price": 24000,
"has_sunroof": true
}
ה. כדי לציין ערכים ריקים או חסרים נשתמש ב-null (כל האותיות קטנות):
{
"name": "BMW",
"price": 24000,
"has_sunroof": true,
"electric": null
}
ו. ערך השדה יכול להיות מערך:
{
"name": "BMW",
"price": 24000,
"has_sunroof": true,
"dimensions": [4.96, 1.87, 1.48]
}
ז. ערך השדה יכול להיות אובייקט:
{
"name": "BMW",
"price": 24000,
"has_sunroof": true,
"dimensions": [4.96, 1.87, 1.48],
"specifications": {
"fuel_type": "petrol",
"max_power": 254.79
}
}
וזה יכול להסתבך כי בתוך אובייקט ניתן לקנן (לשים בתוך) אובייקטים נוספים בכמה רמות של היררכיה.
צריך להקפיד מאוד על כללי התחביר כשכותבים JSON כי ה-API יעבדו רק עם תחביר תקני. בדרך כלל, לא כותבים את ה-JSON ידנית אלא באמצעות פקודה.
אבל אם יצא לכם לכתוב JSON תוכלו להשתמש בלינטרים דוגמת : https://jsonlint.com לבדיקת תקינות הקוד. בנוסף, כל עורך קוד סביר מציע לינטר של JSON.
איך להשתמש ב-JSON כשעובדים עם פייתון?
json הוא מודול מובנה של פייתון. לכן לא צריך להתקין אותו.
הפונקציה loads() של המודול json הופכת את מחרוזת ה-JSON לערך שפייתון יכול להשתמש בו.
לדוגמה:
import json
jsonStr = '{"model": "BMW", "hasSunroof": true, "KMs": 30000, "selfDriving": null}'
pyVal = json.loads(jsonStr)
print(pyVal)
והתוצאה:
{'model': 'BMW', 'hasSunroof': True, 'KMs': 30000, 'selfDriving': None}
נחלץ את השדות:
pyVal['model'] # BMW
pyVal['KMs'] # 30000
pyVal['hasSunroof'] # True
pyVal['selfDriving'] # None
- json.loads() הופך את הערך null ל-None כי הוא יודע לעבוד בפייתון עם None.
סקריפט פייתון להורדת תמונות מסוכנות החלל האמריקאית NASA
הסקריפט מוריד את התמונות היומיות מה-API של NASA. המידע המוחזר הוא בפורמט של JSON. מתוכו נמצה את URL התמונה אותו נעתיק לתיקייה במחשב האישי.
ה-API של NASA הוא חינמי. כדי לצרוך אותו צריך להרשם בכתובת: https://api.nasa.gov מה שמאפשר גישה למזהה ייחודי, app id, שמזהה את האפליקציה שלנו בפני נותן השירות. לדוגמה:
fY2SW6ZMnXXXXXXXVl31OpXXX8dcbMZXXXX8TG34
- אל תשתמשו במזהה הזה כי הוא רק דוגמה.
הסקריפט כולל 3 שלבים:
- הפנייה ל-API.
- הפיכת ה-JSON המוחזר למידע שפייתון יכול להשתמש בו.
- העתקת התמונה לתיקייה במחשב האישי.
הסקריפט המלא
זה הסקריפט המלא. בהמשך תוכלו לקרוא הסבר:
import os, json, requests, shutil
from datetime import date, datetime
# define API URL and params
API_URL = 'https://api.nasa.gov/planetary/apod'
APPID = 'fYFSWzZMnXm7MQBDqlZ1OpXhrAdcqMZd9qA84G34'
dt = str(date.today()) # or a specific date '2020-07-31'
# the path to the directory where you want the pictures
# the path is up to you to detemine
USER_NAME = 'joe'
wallpapers_dir = os.path.join('/home', USER_NAME, 'Pictures', 'wallpapers')
print("Ready to launch")
# create the intented directory if needed
if os.path.exists(wallpapers_dir) == False:
os.mkdir(wallpapers_dir)
# many things might go wrong when consuming APIs
try:
print("Request sent to NASA API")
# send the request
params = {'api_key': APPID, 'date': dt}
response = requests.get(API_URL, params=params)
response.raise_for_status()
# print(response.request.url)
# print(response.text)
print("JSON response received from the API")
# make a python variable from the request
pyVal = json.loads(response.text)
# print(pyVal['title'], pyVal['url'])
if pyVal['media_type'] == 'image' :
# copy the image to the intented directory
dt_obj = datetime.strptime(dt, "%Y-%m-%d").date()
dt_str = dt_obj.strftime("%Y_%m_%d")
out_file_name = os.path.join(wallpapers_dir, dt_str + '__' + 'nasa_daily.jpg')
print("Downloading image to " + out_file_name)
response = requests.get(pyVal['url'], stream=True)
with open(out_file_name, 'wb') as out_file:
shutil.copyfileobj(response.raw, out_file)
del response
print("Mission complete")
else:
print("No image to download today")
except requests.exceptions.HTTPError as errh:
print ("Http Error:",errh)
except requests.exceptions.ConnectionError as errc:
print ("Error Connecting:",errc)
except requests.exceptions.Timeout as errt:
print ("Timeout Error:",errt)
except requests.exceptions.RequestException as err:
print ("OOps: Something Else",err)
0. דרישה מקדימה - יבוא מודולים
הקוד תלוי במודולים הבאים שאותם צריך לייבא:
import os, json, requests, shutil
from datetime import date, datetime
את המודולים requests ו- shutil ניתן להתקין באמצעות הרצת הפקודות הבאות בטרמינל:
$ pip3 install requests
$ pip3 install shutil
1. הפנייה ל-API
כדי להוריד את המידע צריך לפנות לכתובת ה-URL של ה-API ולהעביר לה את הפרמטרים:
- מזהה האפליקציה
- תאריך התמונה
# define API URL and params
API_URL = 'https://api.nasa.gov/planetary/apod'
APPID = 'fYHxxx0nXX7dQ9cXqlZXXp989rAdcqVxxxxxxxxxxx'
dt = '2020-07-31' # or today's date str(date.today())
# send the request
params = {'api_key': APPID, 'date': dt}
response = requests.get(API_URL, params=params)
response.raise_for_status()
# print(response.request.url)
print(response.text)
- את הפנייה לכתובת המרוחקת מבצעת הספרייה requests באמצעות הפונקציה requests.get().
- הפונקציה response.raise_for_status() מוודאת שאין שגיאות.
- response.text() כותבת למסך הטרמינל את המידע שהוחזר מה-API.
כך נראה המידע המוחזר:
{"copyright":"John Kraus","date":"2020-07-31","explanation":"On Thursday this snapshot from a small plane 5,000 feet above Florida's Space Coast caught a rocket's trail rising into the blue morning sky. It was July's third launch of a mission from planet Earth bound for Mars. The Atlas V rocket left Cape Canaveral Air Force Station from Space Launch Complex 41 at 7:50am EDT carrying NASA's Mars 2020 Perseverance Rover. The car-sized Perseverance is headed for a landing at Jezero Crater on the Red Planet in February 2021. On board the sophisticated rover is the Ingenuity Mars Helicopter. Mars 2020 Launch: photos from planet Earth","hdurl":"https://apod.nasa.gov/apod/image/2007/Mars2020launchKraus.jpg","media_type":"image","service_version":"v1","title":"Mars 2020 from 5,000 Feet","url":"https://apod.nasa.gov/apod/image/2007/Mars2020launchKraus1024.jpg"}
מה שמוחזר הוא טקסט ארוך ולא ידידותי שנצטרך למצות ממנו את המידע שמעניין אותנו.
2. הפיכת המידע למשתנה של פייתון
השדות "url" ו-"media_type" הם אילו שמעניינים אותנו. נחלץ אותם מתוך המידע המוחזר בעזרת הפונקציה json.loads() שתהפוך את המידע ממחרוזת למשתנה של פייתון:
# make a python variable from the request
pyVal = json.loads(response.text)
נמצה את השדות שמעניינים אותנו:
print(pyVal['media_type'])
print(pyVal['url'])
image https://apod.nasa.gov/apod/image/2007/Mars2020launchKraus1024.jpg
3. העתקת התמונה לתיקייה במחשב האישי
נגדיר את הנתיב אליו נרצה להוריד את התמונה. אצלי על המחשב (לינוקס) בחרתי את הנתיב הבא:
# the path to download
USER_NAME = 'joe'
wallpapers_dir = os.path.join('/home', USER_NAME, 'Pictures', 'wallpapers')
- את הנתיב wallpapers_dir תצטרכו לשנות לנתיב על המחשב שלכם.
הקוד הבא יעתיק את ה-url לתמונה אותה נשמור בתיקייה במחשב האישי:
# only if the resources is an image
if pyVal['media_type'] == 'image' :
# copy the image to the intended directory
dt_obj = datetime.strptime(dt, "%Y-%m-%d").date()
dt_str = dt_obj.strftime("%Y_%m_%d")
out_file_name = os.path.join(wallpapers_dir, dt_str + '__' + 'nasa_daily.jpg')
# print(out_file_name)
response = requests.get(pyVal['url'], stream=True)
with open(out_file_name, 'wb') as out_file:
shutil.copyfileobj(response.raw, out_file)
del response
print("Mission complete")
else:
print("No image to download today")
- קודם כל נוודא שהסוג הוא תמונה (לפעמים השירות מחזיר סרטון).
- requests יקלוט את המידע על התמונה וshutil יצור עותק מקומי.
לכל המדריכים בסדרה ללימוד פייתון
אהבתם? לא אהבתם? דרגו!
0 הצבעות, ממוצע 0 מתוך 5 כוכבים
המדריכים באתר עוסקים בנושאי תכנות ופיתוח אישי. הקוד שמוצג משמש להדגמה ולצרכי לימוד. התוכן והקוד המוצגים באתר נבדקו בקפידה ונמצאו תקינים. אבל ייתכן ששימוש במערכות שונות, דוגמת דפדפן או מערכת הפעלה שונה ולאור השינויים הטכנולוגיים התכופים בעולם שבו אנו חיים יגרום לתוצאות שונות מהמצופה. בכל מקרה, אין בעל האתר נושא באחריות לכל שיבוש או שימוש לא אחראי בתכנים הלימודיים באתר.
למרות האמור לעיל, ומתוך רצון טוב, אם נתקלת בקשיים ביישום הקוד באתר מפאת מה שנראה לך כשגיאה או כחוסר עקביות נא להשאיר תגובה עם פירוט הבעיה באזור התגובות בתחתית המדריכים. זה יכול לעזור למשתמשים אחרים שנתקלו באותה בעיה ואם אני רואה שהבעיה עקרונית אני עשוי לערוך התאמה במדריך או להסיר אותו כדי להימנע מהטעיית הציבור.
שימו לב! הסקריפטים במדריכים מיועדים למטרות לימוד בלבד. כשאתם עובדים על הפרויקטים שלכם אתם צריכים להשתמש בספריות וסביבות פיתוח מוכחות, מהירות ובטוחות.
המשתמש באתר צריך להיות מודע לכך שאם וכאשר הוא מפתח קוד בשביל פרויקט הוא חייב לשים לב ולהשתמש בסביבת הפיתוח המתאימה ביותר, הבטוחה ביותר, היעילה ביותר וכמובן שהוא צריך לבדוק את הקוד בהיבטים של יעילות ואבטחה. מי אמר שלהיות מפתח זו עבודה קלה ?
השימוש שלך באתר מהווה ראייה להסכמתך עם הכללים והתקנות שנוסחו בהסכם תנאי השימוש.