12月04, 2019

Python 做 UI 超 easy!(3.2)——搞定!天气预报小工具

上一节已经大体实现了界面,两个输入框,一个按钮,当然还有两个文本标签。

title

另外我找到了两个免费的天气预报接口

这两个接口返回的数据是 Json 格式,希望你没有忘记。在这些 Json 数据里,就有天气数据,还是四五天的预报,真洋气!感谢接口的提供者!

今天我们一鼓作气,将 Json 数据和视窗程序整合在一起,完成第一个有用的作品。

用 Python 访问网络

你也可以在线运行 requests 实例代码
https://repl.it/@alvendarthy/testRequests

如果对天气预报程序稍作剖析,

  • 它的界面运行在用户这里,也就是我们自己的电脑上,未来分发给朋友们,就会有很多用户。
  • 界面中的数据,城市来自用户输入,天气数据却来自网络。

天气预报小程序的工作场景看起来会是这样:

title

  • 用户的电脑称为客户端(Client),
  • 接口服务器称为服务端(Server)

当你听到别人说,我的服务是 C/S 架构的,说的就是这样的情况。

从用户的电脑到别人的服务器(提供网络接口服务的机器,本质上也是电脑)之间的网络连接,实际情况会比较复杂。借助第三方库 requests,可以简化为上图中的样子。

快速看一下用 requests 库怎样获得网络数据:

# 首先当然是 import
import requests

# 使用 requests 的 get 函数,
# 第一个参数是要访问的 url,这里填写接口的完整连接就可以了,我使用了第一个接口
r = requests.get("http://wthrcdn.etouch.cn/weather_mini?city=北京市")

# 接口的数据在这里
print(r.text, type(r.text))

下面是我运行的结果

title

如果将命令行中第一部分数据(不包含 )粘贴到 在线 json 格式化工具 https://www.json.cn/ 左侧窗口,看到它很像字典格式。但是图中标出的是 type(r.text) 的输出,可以看到接口返回的数据是 String。

如何将 Json 格式的字符串转换为 Python 字典呢?还是要用第三方库 json。继续增加代码:

import requests
# 继续导入
import json

# 使用 requests 的 get 函数,
# 第一个参数是要访问的 url,这里填写接口的完整连接就可以了,我使用了第一个接口
r = requests.get("http://wthrcdn.etouch.cn/weather_mini?city=北京市")

# 接口的数据在这里
print(r.text, type(r.text))

# result 是一个 Python 字典
result = json.loads(r.text)

print("result type:", type(result))

print("tomorrw: ", result["data"]["forecast"][0]["type"])

title

这里用 json.loads(result) 将 r.text 转换为字典:dict 类型,我已经在图中标出。

可以看到通过 result["data"]["forecast"][0]["type"] 就得到了明天的天气,注意 result 嵌套多层,混合了字典和 list。

既然已经可以得到明天的天气了,不如写成函数方便一些。这个函数只接收一个 String 参数:city,就可以了。

import requests
import json

def get_weather(city):
    r = requests.get("http://wthrcdn.etouch.cn/weather_mini?city=" + city)
    result = json.loads(r.text)
    return result["data"]["forecast"][0]["type"]

Tips:
这样的函数可能正常工作,也可能异常,生产环境需要处理各种异常情况,确保逻辑严密。
使用 Windows 系统蓝屏的时候,用户会一边重启,以便诅咒开发者。
所以你懂得,对用户好一点。
异常处理是单独的 Python 话题,你可以在 “菜鸟教程” 和百度上获得更多资料。

合体!

你也可以在这里在线运行合体以后的代码
https://repl.it/@alvendarthy/PySimpleGUIDemo3

不要忘记导入所有需要用的库: PySimpleGUI、requests、json,把我们写好的获取天气的函数也添加进来。

TIPS:
在线环境不支持中文,所以我使用了城市编号接口,在输入窗要输入城市编号,北京的编码是 101010100,其他城市可以在这里查找:
http://mat1.gtimg.com/weather/index2014/wtData_v2.js
你在本地开发的话,就可以将 get_weather 函数中的 url 换成城市名称的接口,方便一些。

import PySimpleGUI as sg
import requests
import json

def get_weather(city):
    # 在线环境不支持中文输入,所以我改用城市编号的接口,如果你在电脑上开发,就不受影响
    r = requests.get("http://wthrcdn.etouch.cn/weather_mini?citykey=" + city)
    result = json.loads(r.text)
    return result["data"]["forecast"][0]["type"]


# 让所有文本居中
sg.SetOptions(text_justification='center') 

layout = [ 
           [ sg.Text("City", size = (20, 1)), sg.Input(key = "-CITY-") ],
           [ sg.Text("Weather", size = (20, 1)), sg.Input(key = "-WEATHER-") ],
           [ sg.Button("Submit")]
         ]

window = sg.Window("Weather App", layout)

event, values = window.read()

print(event, values)

# values 是一个字典,访问可输入组件的 key(定义蓝图时指定了这个参数)可以获得组件的输入
city = values["-CITY-"]

weather = get_weather(city)

print(weather)

window.close()

点击 run,在 city 一栏输入北京的城市编码 101010100, 点击 submit 按钮。

title

看,已经成功得到天气了。下面,我们让天气显示到 Weather 窗口中。

可输入组件除了可以接受用户的输入外,也可以用代码控制,需要用到 Input 类的 update 方法,它的参数就是输入框中要展现的字符串,当然就是天气字符串了。

TIPS:
你猜怎么清空输入框? 说出来你都不信,update 的参数填写空字符串 “” 就好了!

就剩最后一步了,加油! 下面我们将天气更新到天气框中。之前我们讲过,视窗里的所有组件,都是在蓝图的 list 中定义的,突然要用到 Input 对象,怎么找到它呢?你当然可以通过 layout[1][1] 这样去访问,有更优雅的做法:

window["-INPUT-"]

超简单不是么!这个特性对版本有要求,如果提示错误,你可以选择升级 PySimpleGUI 或者使用经典方法:

  • window.Element("-INPUT-")
  • window.FindElement("-INPUT-")

它们都是等效的。用这种方法的好处是,当你修改蓝图的时候,只要组件的 key 唯一,你就不需要修改其他代码。

import PySimpleGUI as sg
import requests
import json

def get_weather(city):
    # 在线环境不支持中文输入,所以我改用城市编号的接口,如果你在电脑上开发,就不受影响
    r = requests.get("http://wthrcdn.etouch.cn/weather_mini?citykey=" + city)
    result = json.loads(r.text)
    return result["data"]["forecast"][0]["type"]


# 让所有文本居中
sg.SetOptions(text_justification='center') 

layout = [ 
           [ sg.Text("City", size = (20, 1)), sg.Input(key = "-CITY-") ],
           [ sg.Text("Weather", size = (20, 1)), sg.Input(key = "-WEATHER-") ],
           [ sg.Button("Submit")]
         ]

window = sg.Window("Weather App", layout)

event, values = window.read()

print(event, values)

# values 是一个字典,访问可输入组件的 key(定义蓝图时指定了这个参数)可以获得组件的输入
city = values["-CITY-"]

weather = get_weather(city)

print(weather)

# 找到天气输入框
weather_wind = window["-WEATHER-"]

# 将天气更新到输入框
weather_wind.update(weather)

# 如果没有这一行,程序会一闪而退,你根本看不到效果
window.read()

window.close()

title

天气一栏,就是 “晴” 了,如果你在本地就一定不会有这样的问题!

太棒了!

学以致用,今天已经开发了一个实际的小工具。别看它功能简单,在此基础上继续添砖加瓦,总会变成理想的那个样子。

明天我们回过头在看一下 PySimpleGUI,了解更多它的细节。

本文链接:http://www.thinkinpython.com/post/PySimpleGUIDemo_3_2.html

-- EOF --