在网络时代,我们随时可能要关注的信息之一就是天气,在本文中我们使用HTTP请求来从网站上抓取天气信息的JSON数据,并使用Qt中有关JSON数据处理类来完成对这些数据的解析,并提取天气状态(阴,晴,雨等),最低最高温,风力,感冒指数等信息并显示出来。
PyQt中对JSON的支持
JSON是一种编码来自Javascript的对象数据的格式,现已广泛用作Internet上的数据交换格式。PyQt提供了处理JSON数据的支持。
PyQt中的JSON支持包括以下类:
- QJsonDocument:读写JSON文档的方式
- QJsonParseError:用于在JSON解析期间报告错误
- QJsonValue:将值封装在JSON中
QJsonDocument
QJsonDocument类提供了一种读取和写入JSON文档的方法。QJsonDocument是包装完整的JSON文档的类,可以从基于UTF-8编码的文本表示形式以及Qt自己的二进制格式读取和写入此文档。使用QJsonDocument. fromJson()将JSON文档从其基于文本的表示形式转换为QJsonDocument. 使用toJson()将其转换回文本。
常用函数:
- fromJson(json, error): 静态方法, 将json解析为UTF-8编码的JSON文档,并从中创建QJsonDocument。如果解析成功,则返回有效的QJsonDocument。如果失败,则返回的文档将为null,并且可选的error变量将包含有关该错误的更多详细信息。
- toJson(self): 将QJsonDocument转换为缩进的UTF-8编码的JSON文档。
QJsonParseError
QJsonParseError类用于在JSON解析期间报告错误。错误类型由枚举量QJsonParseError.ParseError表示:
- QJsonParseError.NoError (0): 没有发生错误
- QJsonParseError.UnterminatedObject (1): 对象未正确用大括号括起来
- QJsonParseError.MissingNameSeparator (2): 缺少分隔不同项目的逗号
- QJsonParseError.UnterminatedArray (3): 数组未正确用方括号括起来
- QJsonParseError.MissingValueSeparator (4): 缺少将键与对象内的值分隔开的冒号
- QJsonParseError.IllegalValue (5): 该值是非法的
- QJsonParseError.TerminationByNumber (6): 输入流在解析数字时结束
- QJsonParseError.IllegalNumber (7): 数字格式不正确
- QJsonParseError.IllegalEscapeSequence (8): 输入中发生非法的转义序列
- QJsonParseError.IllegalUTF8String (9): 输入中出现非法的UTF8序列
- QJsonParseError.UnterminatedString (10): 字符串未以引号终止
- QJsonParseError.MissingObject (11): 预期有一个对象,但找不到
- QJsonParseError.DeepNesting (12): JSON文档的嵌套太深,解析器无法对其进行解析
- QJsonParseError.DocumentTooLarge (13): JSON文档太大,解析器无法解析它
- QJsonParseError.GarbageAtEnd (14): 解析的文档末尾包含其他垃圾字符
QJsonParseError常用函数:
- errorString(self):返回适合于所报告的JSON解析错误的人类可读信息。
QJsonValue
JSON是一种存储结构化数据的格式。它具有6种基本数据类型:
- QJsonValue.Null: 空类型
- QJsonValue.Bool:布尔型
- QJsonValue.Double:双精度浮点数
- QJsonValue.String:字符串
- QJsonValue.Array:数组
- QJsonValue.Object:对象类型
城市天气信息演示
代码演示了使用Http请求从网站中下载天气信息,并使用Qt提供的JSON支持,将数据解析提出出来,显示在界面上,在程序中, 省会级一些知名城市可以直接选择,然后获得天气信息,也可以手动输入城市名来查询天气信息。完整代码如下:
import sysfrom PyQt5 import QtCore, QtGui, QtWidgetsfrom PyQt5.QtCore import Qt, QJsonDocument, QJsonParseError, QUrl, pyqtSignalfrom PyQt5.QtWidgets import (QApplication, QWidget, QLabel, QPushButton, QLineEdit, QGroupBox,QComboBox, QVBoxLayout, QHBoxLayout, QFormLayout, QFrame, QPlainTextEdit)from PyQt5.QtNetwork import QNetworkRequest, QNetworkAccessManager, QNetworkReply class DemoWeather(QWidget): getWeather = pyqtSignal(bool) def __init__(self, parent=None): super(DemoWeather, self).__init__(parent) # 设置窗口标题 self.setWindowTitle('实战 Qt for Python: 天气信息查询') # 设置窗口大小 self.resize(420, 200) self.initUi() #保存数据 self.comfortLevel = '' #舒适度(感冒指数) self.cityName='' #城市名称 self.weather='' #天气类型 self.temperature='' #温度范围 self.wind='' #风 self.nam = QNetworkAccessManager(self) self.nam.finished.connect(self.replyFinished) self.getWeather.connect(self.slotGetWeather) #初始情况,加入北京的天气 self.getWeatherData('北京') #设置外观界面 def initUi(self): #采用选择方式查询 cities = ['北京', '天津', '上海', '重庆', '哈尔滨', '长春', '沈阳', '石家庄', '济南', '郑州', '太原', '西安','呼和浩特', '银川', '兰州', '西宁','乌鲁木齐', '拉萨', '昆明', '成都', '贵阳','南宁', '广州', '海口', '福州', '南昌', '长沙', '武汉', '合肥', '南京', '杭州', '台北', '香港', '澳门', '深圳', '厦门', '青岛', '大连'] self.comboBoxCity = QComboBox() self.comboBoxCity.addItems(cities) self.comboBoxCity.activated.connect(self.selectCityChanged) labelCity = QLabel('城市(&C)') labelCity.setBuddy(self.comboBoxCity) cityLayout = QFormLayout() cityLayout.setSpacing(16) cityLayout.addRow(labelCity, self.comboBoxCity) #手动输入城市的方式查询 grpBox = QGroupBox('手动查询(&M)') grpBox.setMaximumWidth(120) self.editCity = QLineEdit() #输入完成敲回车键查询 self.editCity.returnPressed.connect(self.slotQueryWeather) btnQuery = QPushButton('查询') btnQuery.clicked.connect(self.slotQueryWeather) manualLayout = QFormLayout() manualLayout.addRow('请输入城市名称:', self.editCity) manualLayout.addRow('', btnQuery) grpBox.setLayout(manualLayout) #左边的布局 leftLayout = QVBoxLayout() leftLayout.setSpacing(20) leftLayout.addLayout(cityLayout) leftLayout.addWidget(grpBox) leftLayout.addStretch(1) #右边信息显示 self.showCity = QLineEdit() self.showCity.setReadOnly(True) self.showWeather = QLineEdit() self.showWeather.setReadOnly(True) self.showTemperature = QLineEdit() self.showTemperature.setReadOnly(True) self.showWind = QLineEdit() self.showWind.setReadOnly(True) self.showComfortLevel = QPlainTextEdit() self.showComfortLevel.setReadOnly(True) #右边的布局 rightLayout = QFormLayout() rightLayout.addRow('城市:', self.showCity) rightLayout.addRow('天气:', self.showWeather) rightLayout.addRow('温度:', self.showTemperature) rightLayout.addRow('风力', self.showWind) rightLayout.addRow('感冒指数:', self.showComfortLevel) #分隔线 spacerLine = QFrame() spacerLine.setFrameShape(QFrame.VLine) mainLayout = QHBoxLayout() mainLayout.setSpacing(16) mainLayout.addLayout(leftLayout) mainLayout.addWidget(spacerLine) mainLayout.addLayout(rightLayout) self.setLayout(mainLayout) def selectCityChanged(self): cityName = self.comboBoxCity.currentText() self.getWeatherData(cityName) def slotQueryWeather(self): cityName = self.editCity.text() self.getWeatherData(cityName) #从网络上获得指定城市的天气数据信息 def getWeatherData(self, cityName): url = 'http://wthrcdn.etouch.cn/weather_mini?city=%s' % cityName print(url) self.nam.get(QNetworkRequest(QUrl(url))) #接收网络的回复数据 def replyFinished(self, reply): data = reply.readAll() #编码转换 #text = bytes.decode(data.data(), encoding='utf8') #print(text) self.processReplyData(data) reply.deleteLater() #解析接收到的数据 def processReplyData(self, data): desc = '' jsonErr = QJsonParseError() jsonDoc = QJsonDocument.fromJson(data, jsonErr) if jsonDoc.isNull(): #空对象,返回 return rootObj = jsonDoc.object() if 'data' in rootObj: dataObj = rootObj['data'].toObject() if 'forecast' in dataObj: forecastObj = dataObj['forecast'] if forecastObj.isArray(): valArray = forecastObj.toArray() #只取当天的数据 val = valArray[0].toObject() self.weather=val['type'].toString() #天气类型 lowTemp=val['low'].toString() #最低温度 highTemp=val['high'].toString() #最高温度 self.temperature=lowTemp[2:] + ' -' + highTemp[2:] fengxiang = val['fengxiang'].toString() fengli = val['fengli'].toString() self.wind = fengxiang + fengli[9:-3] if 'city' in dataObj: cityObj = dataObj['city'] if cityObj.isString(): self.cityName = cityObj.toString() if 'ganmao': #舒适度指数 ganmaoObj = dataObj['ganmao'] if ganmaoObj.isString(): self.comfortLevel = ganmaoObj.toString() if 'desc' in rootObj: #描述信息 descObj = rootObj['desc'] if descObj.isString(): desc = descObj.toString() if desc == 'OK': self.getWeather.emit(True) else: self.getWeather.emit(False) def slotGetWeather(self, isGet): if isGet: self.showCity.setText(self.cityName) self.showWeather.setText(self.weather) self.showTemperature.setText(self.temperature) self.showWind.setText(self.wind) self.showComfortLevel.setPlainText(self.comfortLevel) else: self.showCity.setText('没有该城市天气信息') self.showWeather.setText('') self.showTemperature.setText('') self.showWind.setText('') self.showComfortLevel.setPlainText('') if __name__ == '__main__': app = QApplication(sys.argv) window = DemoWeather() window.show() sys.exit(app.exec())
运行结果如下图:
本文知识点
- QT对JSON数据的支持;
- 使用HTTP请求下载城市天气信息;
- JSON数据解析方法。
前一篇:实战PyQt5: 130-使用HTTP请求下载文件