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.