For the meanings of the fields of the URL and the fields of the output, see Call current weather data for one location.
The data downloaded from the URL is a
sequence
of bytes,
not a
string
of characters.
That’s why we have to feed the data to
decode
.
The current weather is one long line line of output.
{"coord":{"lon":-74.02,"lat":40.69},"weather":[{"id":521,"main":"Rain","description":"shower rain","icon":"09n"},{"id":701,"main":"Mist","description":"mist","icon":"50n"},{"id":711,"main":"Smoke","description":"smoke","icon":"50n"}],"base":"stations","main":{"temp":77.95,"pressure":1009,"humidity":88,"temp_min":73.99,"temp_max":84.2},"visibility":6437,"wind":{"speed":4.7,"deg":320,"gust":23.04},"rain":{"1h":4.91},"clouds":{"all":90},"dt":1570056296,"sys":{"type":1,"id":4026,"message":0.0127,"country":"US","sunrise":1570013592,"sunset":1570055855},"timezone":-14400,"id":5128581,"name":"New York","cod":200} {'coord': {'lon': -74.02, 'lat': 40.69}, 'weather': [{'id': 521, 'main': 'Rain', 'description': 'shower rain', 'icon': '09n'}, {'id': 701, 'main': 'Mist', 'description': 'mist', 'icon': '50n'}, {'id': 711, 'main': 'Smoke', 'description': 'smoke', 'icon': '50n'}], 'base': 'stations', 'main': {'temp': 77.95, 'pressure': 1009, 'humidity': 88, 'temp_min': 73.99, 'temp_max': 84.2}, 'visibility': 6437, 'wind': {'speed': 4.7, 'deg': 320, 'gust': 23.04}, 'rain': {'1h': 4.91}, 'clouds': {'all': 90}, 'dt': 1570056296, 'sys': {'type': 1, 'id': 4026, 'message': 0.0127, 'country': 'US', 'sunrise': 1570013592, 'sunset': 1570055855}, 'timezone': -14400, 'id': 5128581, 'name': 'New York', 'cod': 200} { "base": "stations", "clouds": { "all": 90 }, "cod": 200, "coord": { "lat": 40.69, "lon": -74.02 }, "dt": 1570056296, "id": 5128581, "main": { "humidity": 88, "pressure": 1009, "temp": 77.95, "temp_max": 84.2, "temp_min": 73.99 }, "name": "New York", "rain": { "1h": 4.91 }, "sys": { "country": "US", "id": 4026, "message": 0.0127, "sunrise": 1570013592, "sunset": 1570055855, "type": 1 }, "timezone": -14400, "visibility": 6437, "weather": [ { "description": "shower rain", "icon": "09n", "id": 521, "main": "Rain" }, { "description": "mist", "icon": "50n", "id": 701, "main": "Mist" }, { "description": "smoke", "icon": "50n", "id": 711, "main": "Smoke" } ], "wind": { "deg": 320, "gust": 23.04, "speed": 4.7 } } temperature = 77.95° Fahrenheit temperature = 77.95° Fahrenheit description = shower rain
import urllib.parse
query = { #query is a dictionary "q": "10004,US", "units": "imperial", "mode": "json", "APPID": "532d313d6a9ec4ea93eb89696983e369" } params = urllib.parse.urlencode(query) #params is a string url = f"http://api.openweathermap.org/data/2.5/weather?{params}"
import datetime
try: dt = bigDictionary["dt"] #dt is an int except KeyError: print("bigDictionary has no key named dt", file = sys.stderr) sys.exit(1) print(f"dt = {dt:,} seconds after midnight on January 1, 1970") localDateAndTime = datetime.datetime.fromtimestamp(dt) #localDateAndTime is a datetime.datetime print(f"localDateAndTime = {localDateAndTime}") print(localDateAndTime.strftime("%c")) print(localDateAndTime.strftime("%A, %B %-d, %Y %-I:%M:%S %p"))
dt = 1,570,056,296 seconds after midnight on January 1, 1970 localDateAndTime = 2019-10-02 18:44:56 Wed Oct 2 18:44:56 2019 Wednesday, October 2, 2019 6:44:56 PM
Print the sunrise and sunset times too.
Ask the macOS and Linux “binary calculator” for answers with up to five digits to the right of the decimal point.
bc -l scale = 5 60 * 60 * 24 * 365.25 * (2019 - 1970) 1546322400.00 control-d
import tkinter
weather = bigDictionary["weather"] #weather is a list. d = weather[0] #d is a dictionary. icon = d["icon"] #icon is a string url = f"http://openweathermap.org/img/wn/{icon}@2x.png" #also try it without the @2x infile = urllib.request.urlopen(url) #error checking omitted for brevity sequenceOfBytes = infile.read() infile.close() root = tkinter.Tk() try: myImage = tkinter.PhotoImage(data = sequenceOfBytes) except tkinter.TclError as error: print(error, file = sys.stderr) sys.exit(1) label = tkinter.Label(root, image = myImage) label.pack() root.mainloop()
tkinter
interface.
""" weather.py Display the current weather (including icon) in different cities. """ import sys import urllib.parse import urllib.request import json import tkinter zipcodes = { "Atlanta": "30301", "Boston": "02109", "Chicago": "60007", "Denver": "80202", "Houston": "77001", "Los Angeles": "90001", "Miami": "33101", "New York": "10004", "San Francisco": "94102", "Seattle": "98101" } defaultCity = "New York" citynames = zipcodes.keys() maxLen = len(max(citynames, key = len)) #length of longest name #data is a tuple containing 5 smaller tuples. #The second half of the last 4 of them is a function. data = ( ("Select your city", None), ("Temperature", lambda d: f'{int(d["main"]["temp"])}° F'), ("Wind speed", lambda d: f'{int(d["wind"]["speed"])} mph'), ("Humidity", lambda d: f'{d["main"]["humidity"]}%'), ("Skies", lambda d: f'{d["weather"][0]["description"]}') ) backgroundColor = { #of the tkinter.Label that displays the icon "d": "sky blue", #day "n": "midnight blue" #night } #This function is called when the program is launched, #and when the user selects a city. def command(cityname): query = { #query is a dictionary "q": f"{zipcodes[cityname]},US", "units": "imperial", "mode": "json", "APPID": "532d313d6a9ec4ea93eb89696983e369" } params = urllib.parse.urlencode(query) #params is a string url = f"http://api.openweathermap.org/data/2.5/weather?{params}" try: infile = urllib.request.urlopen(url) except urllib.error.URLError as error: print(error, url, file = sys.stderr) sys.exit(1) sequenceOfBytes = infile.read() #Read the entire input file. infile.close() try: s = sequenceOfBytes.decode("utf-8") #s is a string. except UnicodeError as error: print(error, file = sys.stderr) sys.exit(1) try: bigDict = json.loads(s) except json.JSONDecodeError as error: print(error, file = sys.stderr) sys.exit(1) assert isinstance(bigDict, dict) for label, datum in zip(labels, data[1:]): label["text"] = datum[1](bigDict) weather = bigDict["weather"][0] #bigDict["weather"] is a list. icon = weather["icon"] #first characters of name of icon file url = f'http://openweathermap.org/img/wn/{icon}@2x.png' try: infile = urllib.request.urlopen(url) except urllib.error.URLError as error: print(error, file = sys.stderr) sys.exit(1) sequenceOfBytes = infile.read() infile.close() try: image = tkinter.PhotoImage(data = sequenceOfBytes) except tkinter.TclError as error: print(error, file = sys.stderr) sys.exit(1) try: bg = backgroundColor[icon[-1]] except KeyError: iconLabel.configure(image = image) else: iconLabel.configure(image = image, bg = bg) iconLabel.image = image #Strange that you need this too. #Create the tkinter interface when the program is launched. root = tkinter.Tk() root.title("Current weather") padx = 5 #dropdown menu dropVariable = tkinter.StringVar(root) dropVariable.set(defaultCity) menu = tkinter.OptionMenu(root, dropVariable, *citynames, command = command) menu.config(width = maxLen) menu.grid(row = 0, column = 1, sticky = "ew") #Create the labels that are captions. for row, datum in enumerate(data): label = tkinter.Label(text = f"{datum[0]}:", anchor = "e", padx = padx) label.grid(row = row, column = 0, sticky = "ew") #Create the labels that display information. labels = [] for row in range(1, len(data)): label = tkinter.Label(anchor = "w", padx = padx, fg = "blue") label.grid(row = row, column = 1, sticky = "ew") labels.append(label) iconLabel = tkinter.Label(root) iconLabel.grid(row = len(data), column = 0, columnspan = 2, sticky = "ew") command(defaultCity) #Begin by displaying the data for the default city. tkinter.mainloop()
Daytime in New York, nighttime in Seattle:
https://maps.googleapis.com/maps/api/geocode/json?address=11+West+42nd+Street,+New+York,+NY+10036
{ "results" : [ { "address_components" : [ { "long_name" : "11", "short_name" : "11", "types" : [ "street_number" ] }, { "long_name" : "West 42nd Street", "short_name" : "W 42nd St", "types" : [ "route" ] }, { "long_name" : "Manhattan", "short_name" : "Manhattan", "types" : [ "political", "sublocality", "sublocality_level_1" ] }, { "long_name" : "New York", "short_name" : "New York", "types" : [ "locality", "political" ] }, { "long_name" : "New York County", "short_name" : "New York County", "types" : [ "administrative_area_level_2", "political" ] }, { "long_name" : "New York", "short_name" : "NY", "types" : [ "administrative_area_level_1", "political" ] }, { "long_name" : "United States", "short_name" : "US", "types" : [ "country", "political" ] }, { "long_name" : "10036", "short_name" : "10036", "types" : [ "postal_code" ] } ], "formatted_address" : "11 W 42nd St, New York, NY 10036, USA", "geometry" : { "location" : { "lat" : 40.7541476, "lng" : -73.9818586 }, "location_type" : "ROOFTOP", "viewport" : { "northeast" : { "lat" : 40.75549658029149, "lng" : -73.98050961970849 }, "southwest" : { "lat" : 40.75279861970849, "lng" : -73.98320758029151 } } }, "place_id" : "ChIJuzzySglZwokRuuz-0i_egSU", "types" : [ "street_address" ] } ], "status" : "OK" }
import sys import urllib.request import json url = "https://maps.googleapis.com/maps/api/geocode/json" \ "?address=11+West+42nd+Street,+New+York,+NY+10036" infile = urllib.request.urlopen(url) #error checking omitted for brevity sequenceOfBytes = infile.read() infile.close() s = sequenceOfBytes.decode("utf-8") #error checking omitted for brevity bigDictionary = json.loads(s) #error checking omitted for brevity print(f'status = {bigDictionary["status"]}') if bigDictionary["status"] != "OK": sys.exit(1) results = bigDictionary["results"] #results is a list containing 1 item result = results[0] #result is a dictionary formatted_address = result["formatted_address"] #formatted_address is a string print(f"formatted_address = {formatted_address}") geometry = result["geometry"] #geometry is a dictionary containing 3 items location = geometry["location"] #location is a dictionary containing 2 items print(f'latitude = {location["lat"]}') print(f'longitude = {location["lng"]}') sys.exit(0)
Positive latitude is north of the equator. Negative longitude is west of Greenwich.
status = OK formatted_address = 11 W 42nd St, New York, NY 10036, USA latitude = 40.7541476 longitude = -73.9818586Add a
tkinter
GUI
to this Python script.
githubusers.py
{ "incomplete_results": false, "items": [ { "avatar_url": "https://avatars3.githubusercontent.com/u/54085829?v=4", "events_url": "https://api.github.com/users/sf19pb1-k1chan/events{/privacy}", "followers_url": "https://api.github.com/users/sf19pb1-k1chan/followers", "following_url": "https://api.github.com/users/sf19pb1-k1chan/following{/other_user}", "gists_url": "https://api.github.com/users/sf19pb1-k1chan/gists{/gist_id}", "gravatar_id": "", "html_url": "https://github.com/sf19pb1-k1chan", "id": 54085829, "login": "sf19pb1-k1chan", "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MDg1ODI5", "organizations_url": "https://api.github.com/users/sf19pb1-k1chan/orgs", "received_events_url": "https://api.github.com/users/sf19pb1-k1chan/received_events", "repos_url": "https://api.github.com/users/sf19pb1-k1chan/repos", "score": 41.05616, "site_admin": false, "starred_url": "https://api.github.com/users/sf19pb1-k1chan/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/sf19pb1-k1chan/subscriptions", "type": "Organization", "url": "https://api.github.com/users/sf19pb1-k1chan" }, { "avatar_url": "https://avatars2.githubusercontent.com/u/54280012?v=4", "events_url": "https://api.github.com/users/sf19pb1-hardeep-leyl/events{/privacy}", "followers_url": "https://api.github.com/users/sf19pb1-hardeep-leyl/followers", "following_url": "https://api.github.com/users/sf19pb1-hardeep-leyl/following{/other_user}", "gists_url": "https://api.github.com/users/sf19pb1-hardeep-leyl/gists{/gist_id}", "gravatar_id": "", "html_url": "https://github.com/sf19pb1-hardeep-leyl", "id": 54280012, "login": "sf19pb1-hardeep-leyl", "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MjgwMDEy", "organizations_url": "https://api.github.com/users/sf19pb1-hardeep-leyl/orgs", "received_events_url": "https://api.github.com/users/sf19pb1-hardeep-leyl/received_events", "repos_url": "https://api.github.com/users/sf19pb1-hardeep-leyl/repos", "score": 37.516575, "site_admin": false, "starred_url": "https://api.github.com/users/sf19pb1-hardeep-leyl/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/sf19pb1-hardeep-leyl/subscriptions", "type": "Organization", "url": "https://api.github.com/users/sf19pb1-hardeep-leyl" }, { "avatar_url": "https://avatars0.githubusercontent.com/u/54124365?v=4", "events_url": "https://api.github.com/users/sf19pb1-petercooper/events{/privacy}", "followers_url": "https://api.github.com/users/sf19pb1-petercooper/followers", "following_url": "https://api.github.com/users/sf19pb1-petercooper/following{/other_user}", "gists_url": "https://api.github.com/users/sf19pb1-petercooper/gists{/gist_id}", "gravatar_id": "", "html_url": "https://github.com/sf19pb1-petercooper", "id": 54124365, "login": "sf19pb1-petercooper", "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MTI0MzY1", "organizations_url": "https://api.github.com/users/sf19pb1-petercooper/orgs", "received_events_url": "https://api.github.com/users/sf19pb1-petercooper/received_events", "repos_url": "https://api.github.com/users/sf19pb1-petercooper/repos", "score": 33.525013, "site_admin": false, "starred_url": "https://api.github.com/users/sf19pb1-petercooper/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/sf19pb1-petercooper/subscriptions", "type": "Organization", "url": "https://api.github.com/users/sf19pb1-petercooper" }, { "avatar_url": "https://avatars3.githubusercontent.com/u/54157444?v=4", "events_url": "https://api.github.com/users/sf19pb1-dannyphu/events{/privacy}", "followers_url": "https://api.github.com/users/sf19pb1-dannyphu/followers", "following_url": "https://api.github.com/users/sf19pb1-dannyphu/following{/other_user}", "gists_url": "https://api.github.com/users/sf19pb1-dannyphu/gists{/gist_id}", "gravatar_id": "", "html_url": "https://github.com/sf19pb1-dannyphu", "id": 54157444, "login": "sf19pb1-dannyphu", "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MTU3NDQ0", "organizations_url": "https://api.github.com/users/sf19pb1-dannyphu/orgs", "received_events_url": "https://api.github.com/users/sf19pb1-dannyphu/received_events", "repos_url": "https://api.github.com/users/sf19pb1-dannyphu/repos", "score": 32.648464, "site_admin": false, "starred_url": "https://api.github.com/users/sf19pb1-dannyphu/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/sf19pb1-dannyphu/subscriptions", "type": "Organization", "url": "https://api.github.com/users/sf19pb1-dannyphu" }, { "avatar_url": "https://avatars3.githubusercontent.com/u/54147861?v=4", "events_url": "https://api.github.com/users/SF19PB1-MarkMeretzky/events{/privacy}", "followers_url": "https://api.github.com/users/SF19PB1-MarkMeretzky/followers", "following_url": "https://api.github.com/users/SF19PB1-MarkMeretzky/following{/other_user}", "gists_url": "https://api.github.com/users/SF19PB1-MarkMeretzky/gists{/gist_id}", "gravatar_id": "", "html_url": "https://github.com/SF19PB1-MarkMeretzky", "id": 54147861, "login": "SF19PB1-MarkMeretzky", "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MTQ3ODYx", "organizations_url": "https://api.github.com/users/SF19PB1-MarkMeretzky/orgs", "received_events_url": "https://api.github.com/users/SF19PB1-MarkMeretzky/received_events", "repos_url": "https://api.github.com/users/SF19PB1-MarkMeretzky/repos", "score": 24.493538, "site_admin": false, "starred_url": "https://api.github.com/users/SF19PB1-MarkMeretzky/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/SF19PB1-MarkMeretzky/subscriptions", "type": "Organization", "url": "https://api.github.com/users/SF19PB1-MarkMeretzky" }, { "avatar_url": "https://avatars2.githubusercontent.com/u/54218787?v=4", "events_url": "https://api.github.com/users/sf19pb1-ffranklin3/events{/privacy}", "followers_url": "https://api.github.com/users/sf19pb1-ffranklin3/followers", "following_url": "https://api.github.com/users/sf19pb1-ffranklin3/following{/other_user}", "gists_url": "https://api.github.com/users/sf19pb1-ffranklin3/gists{/gist_id}", "gravatar_id": "", "html_url": "https://github.com/sf19pb1-ffranklin3", "id": 54218787, "login": "sf19pb1-ffranklin3", "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MjE4Nzg3", "organizations_url": "https://api.github.com/users/sf19pb1-ffranklin3/orgs", "received_events_url": "https://api.github.com/users/sf19pb1-ffranklin3/received_events", "repos_url": "https://api.github.com/users/sf19pb1-ffranklin3/repos", "score": 24.107796, "site_admin": false, "starred_url": "https://api.github.com/users/sf19pb1-ffranklin3/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/sf19pb1-ffranklin3/subscriptions", "type": "Organization", "url": "https://api.github.com/users/sf19pb1-ffranklin3" }, { "avatar_url": "https://avatars1.githubusercontent.com/u/54335653?v=4", "events_url": "https://api.github.com/users/SF19PB1-ructr/events{/privacy}", "followers_url": "https://api.github.com/users/SF19PB1-ructr/followers", "following_url": "https://api.github.com/users/SF19PB1-ructr/following{/other_user}", "gists_url": "https://api.github.com/users/SF19PB1-ructr/gists{/gist_id}", "gravatar_id": "", "html_url": "https://github.com/SF19PB1-ructr", "id": 54335653, "login": "SF19PB1-ructr", "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MzM1NjUz", "organizations_url": "https://api.github.com/users/SF19PB1-ructr/orgs", "received_events_url": "https://api.github.com/users/SF19PB1-ructr/received_events", "repos_url": "https://api.github.com/users/SF19PB1-ructr/repos", "score": 18.845026, "site_admin": false, "starred_url": "https://api.github.com/users/SF19PB1-ructr/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/SF19PB1-ructr/subscriptions", "type": "Organization", "url": "https://api.github.com/users/SF19PB1-ructr" }, { "avatar_url": "https://avatars0.githubusercontent.com/u/54126431?v=4", "events_url": "https://api.github.com/users/sf19pb1-jhjhjhsu/events{/privacy}", "followers_url": "https://api.github.com/users/sf19pb1-jhjhjhsu/followers", "following_url": "https://api.github.com/users/sf19pb1-jhjhjhsu/following{/other_user}", "gists_url": "https://api.github.com/users/sf19pb1-jhjhjhsu/gists{/gist_id}", "gravatar_id": "", "html_url": "https://github.com/sf19pb1-jhjhjhsu", "id": 54126431, "login": "sf19pb1-jhjhjhsu", "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0MTI2NDMx", "organizations_url": "https://api.github.com/users/sf19pb1-jhjhjhsu/orgs", "received_events_url": "https://api.github.com/users/sf19pb1-jhjhjhsu/received_events", "repos_url": "https://api.github.com/users/sf19pb1-jhjhjhsu/repos", "score": 17.24035, "site_admin": false, "starred_url": "https://api.github.com/users/sf19pb1-jhjhjhsu/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/sf19pb1-jhjhjhsu/subscriptions", "type": "Organization", "url": "https://api.github.com/users/sf19pb1-jhjhjhsu" } ], "total_count": 8 } bigDictionary["incomplete_results"] = False bigDictionary["total_count"] = 8 type(bigDictionary["items"]) = <class 'list'> len(bigDictionary["items"]) = 8 1 https://github.com/sf19pb1-dannyphu 2 https://github.com/sf19pb1-ffranklin3 3 https://github.com/sf19pb1-hardeep-leyl 4 https://github.com/sf19pb1-jhjhjhsu 5 https://github.com/sf19pb1-k1chan 6 https://github.com/SF19PB1-MarkMeretzky 7 https://github.com/sf19pb1-petercooper 8 https://github.com/SF19PB1-ructr
http://api.openweathermap.org/data/2.5/weather
https://maps.googleapis.com/maps/api/geocode/json
https://api.github.com/search/users
When all else fails, there’s always
http://www.jsontest.com/
,
e.g.