עזבו אדומות, בואו נגלה מי הערים הירוקות בעזרת פייתון
פוסט זה כולל טיפ קצר לעבודה יעילה עם Python. אם אתם רוצים ללמוד פייתון יותר לעומק אני ממליץ על קורס Python כאן באתר.
הקורס כולל עשרות שיעורי וידאו והמון תרגול מעשי וילמד אתכם Python בצורה מקצועית מההתחלה ועד הנושאים המתקדמים.
כולם מדברים רק על הערים האדומות ואני יכול להבין את זה: אדום זה סכנה, זה מפחיד, זה סגר, זה קורונה. אבל אולי דווקא אתם הטיפוסים שמעדיפים לשמוע שהעיר שלכם ירוקה? או לפחות לחפש איזו עיר ירוקה לברוח אליה?
אז משרד הבריאות יצא בסדר והשיק יופי של אתר עם API מאחוריו כדי שאנחנו נוכל לשחק עם הנתונים בצורה שאנחנו רוצים. כתובת האתר היא:
https://www.gov.il/he/Departments/DynamicCollectors/cities-ramzor
אבל אותנו יעניין ה API שמאחוריו. עכשיו מסיבה שאני לא לגמרי מבין שירותי ממשלה שכבר טורחים ומפתחים API לא ממש להוטים לספר עליו. מכל מקום אפשר להשתמש בכלי הפיתוח של הדפדפן כדי לראות את המידע שעובר ברשת בגלישה באתר וזה הוביל אותי לכתובת:
https://www.gov.il/he/api/DataGovProxy/GetDGResults
שכבר החזירה לי את הנתונים בתוך JSON מסודר. עכשיו עם המידע הזה נוכל להתקדם ולכתוב קוד פייתון כדי להוריד ולהציג את הנתונים בצורה ידידותית, ולגלות את רשימת כל הערים הירוקות.
1. סקריפט 1 - שמירת נתוני הערים
בגלל שאין המון מידע אפשר להשתמש בספריה requests ולרוץ בלולאה פשוטה כדי למשוך את כולו. למחשב שלי לקח קצת פחות מ-4 שניות למשוך את כל המידע לקובץ JSON שזה ממש בסדר.
כל פניה ל API מחזירה 10 תוצאות נוספות, והקוד פשוט פונה בלולאה וכל פעם מדלג על 10 * i
תוצאות ראשונות כדי להוריד 10 תוצאות נוספות. את סך כל התוצאות מצאתי בחיפוש באתר הרגיל שלהם.
זה הקוד במלואו:
import requests
import json
all_data = []
s = requests.Session()
for i in range(0, 1236, 10):
headers = {
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0',
'Accept': 'application/json',
'Accept-Language': 'en-US',
'Referer': 'https://www.gov.il/he/Departments/DynamicCollectors/cities-ramzor?skip=0',
'Content-Type': 'application/json;charset=utf8',
'Origin': 'https://www.gov.il',
'Pragma': 'no-cache',
'Cache-Control': 'no-cache',
}
data = json.dumps({
"DynamicTemplateID": "2dd7aea4-6f64-4eca-8465-98ee82fadd45",
"QueryFilters": {"skip":{"Query":"0"}},
"From": f"{i}"
})
url = 'https://www.gov.il/he/api/DataGovProxy/GetDGResults'
r = s.post(url, headers=headers,data=data)
batch = json.loads(r.text)
all_data.extend(batch['Results'])
with open('data.json', 'w') as fp:
json.dump(all_data, fp)
שימו לב שהוספתי לכתובת גם HTTP Headers. לקחתי את הכותרות שהגיעו מהדפדפן כמו שהן. אני חושב שחלק מהן מיותרות אבל לא התאמצתי לצמצם.
הסקריפט יוצר קובץ JSON בשם data.json
שכולל את כל דירוגי הערים והצבעים שלהן. כך נראית ההתחלה של הקובץ:
[
{
"Data": {
"city_desc": "כפר קאסם",
"score": "10.0",
"link_city": "<b><u><a href=\"https://go.gov.il/red-city\">הנ
חיות והגבלות לישוב >> </a></b></u>",
"Municipality_calc_desc": "כפר קאסם",
"colour_Calc": "אדום",
"citydesc": "ללא",
"city_color": "<img src=\"https://www.gov.il/BlobFolder/generalpage/city-colors/he/Misc_red-city.png\">",
"totalresults": "1236"
},
"Description": null,
"UrlName": null
},
{
"Data": {
"city_desc": "לקיה",
"score": "10.0",
"link_city": "<b><u><a href=\"https://go.gov.il/red-city\">הנ
חיות והגבלות לישוב >> </a></b></u>",
"Municipality_calc_desc": "לקיה",
"colour_Calc": "אדום",
"citydesc": "ללא",
"city_color": "<img src=\"https://www.gov.il/BlobFolder/generalpage/city-colors/he/Misc_red-city.png\">",
"totalresults": "1236"
},
"Description": null,
"UrlName": null
},
...
]
2. סקריפט 2 - קריאת הנתונים ל Data Frame
כשיש לנו נתונים טבלאיים הכי קל לפענח אותם באמצעות Pandas. הקוד הבא יוצר Data Frame מתוך הנתונים:
import pandas as pd
import json
raw_data = json.load(open('data.json'))
raw_data = list(map(lambda entry: entry["Data"], raw_data))
data = pd.DataFrame(raw_data)
data.score = data.score.astype('float')
data.colour_Calc = data.colour_Calc.astype('category')
הקוד טוען את קובץ ה JSON, מושך מכל פריט מידע רק את שדה Data שלו (כי כל המידע שמור בתוך שדה זה) ויוצר Data Frame ממערך האוביקטים שהתקבל.
לאחר מכן אני משנה סוגים של שתי עמודות: את עמודת הניקוד הפכתי למספר ואת עמודת הצבעים לקטגוריה.
מאחר ואנחנו מתעניינים רק ברשימת הערים הירוקות נסיים עם הקוד הבא שידפיס את כל הרשימה:
with pd.option_context('display.max_rows', None, 'display.max_columns', None):
print(data[data.colour_Calc == 'ירוק'].city_desc)