(二)通过网络获取天气信息

这个项目的最终目的是实现在ARM板上,使用qt+opencv实现人脸识别的考勤系统。上一次完成了打开摄像头代码,这一次我打算在系统中加入通过网络实时获取当地天气情况的功能。

 

  • 使用心知天气的API接口实现(免费)

  • 在这里我选择使用心知天气提供的API接口来完成这次任务。JSON格式。

    心知天气的官网网址

    https://www.seniverse.com

    注册登录后,进入控制台,点击我的API项目

  • (二)通过网络获取天气信息_第1张图片

  • 记录好自己的API私钥,这里被和谐了,因为私钥是重要的访问密码,最好不要透露出去。

    因为是免费用户,所以只有3个API接口可以调用,其他的都不能用,访问频率也被限制到400次/小时,或者20次/分钟。(当然如果你是土豪可以考虑花钱购买)超过了访问频率,服务器将会拒绝你的访问,直到一个小时后再恢复。

    然后点击产品文档查看API格式

  • (二)通过网络获取天气信息_第2张图片

  • 点击天气现象代码说明这里,下载官方提供的图标,程序中会用到。至于使用哪个图标就看你自己喜好了。

  • (二)通过网络获取天气信息_第3张图片

  • 接下来看API调用格式,因为是免费用户,可以使用的三个API分别是天气实况,逐日天气和生活指数。

  • 第一个,天气实况

  • (二)通过网络获取天气信息_第4张图片

  • 将这个url地址复制下来,将key=后面的打码部分改为自己的私钥,location=后面的beijing改为ip,其他的不用改。ip的意思是自动根据IP地址定位城市,如果想查询指定的城市,可以通过上面的“接口中的通用参数”了解,这一章对API中的参数设置有详细说明。JSON格式我就不细说了,自己去了解吧。

  • (二)通过网络获取天气信息_第5张图片

  • 第二个,逐日天气

  • (二)通过网络获取天气信息_第6张图片

  • 把url地址复制下来,参数修改如上。

    第三个,生活指数

  • (二)通过网络获取天气信息_第7张图片

  • url地址复制下来。

    API接口记录完毕,接下里开始写代码。

  • Qt重点代码解析

    • 访问API接口,并获取返回的JSON数据

    • 访问网址用到了QT的两个类,QNetworkAccessManager和QNetworkReply

      记得包含头文件和在.pro文件中加入network

    • #include 
      #include 
      #include 
      #include 

      (二)通过网络获取天气信息_第8张图片

    • 在.h文件中声明变量,因为有三个地址,我想同时访问,所以每一个都要创建对应的QNetworkAccessManager和QNetworkReply

    • QNetworkAccessManager *m_NetManger_now;
      QNetworkAccessManager *m_NetManger_daily;
      QNetworkAccessManager *m_NetManger_life;
      
      QNetworkReply *m_Reply_now;
      QNetworkReply *m_Reply_daily;
      QNetworkReply *m_Reply_life;
      

      接着声明槽

    • private slots:
          void finishedSlot_now(QNetworkReply*);
          void finishedSlot_daily(QNetworkReply*);
          void finishedSlot_life(QNetworkReply*);
      

      在.c的构造函数中加入

    • url_weather_now = "https://api.seniverse.com/v3/weather/now.json?key=你自己的私钥&location=ip&language=zh-Hans&unit=c";
      url_weather_daily = "https://api.seniverse.com/v3/weather/daily.json?key=你自己的私钥&location=ip&language=zh-Hans&unit=c&start=0&days=5";
      url_weather_life = "https://api.seniverse.com/v3/life/suggestion.json?key=你自己的私钥&location=ip&language=zh-Hans";
      
      m_NetManger_now = new QNetworkAccessManager;
      m_NetManger_daily = new QNetworkAccessManager;
      m_NetManger_life = new QNetworkAccessManager;
      
      connect(m_NetManger_now,&QNetworkAccessManager::finished,this,&WeatherWidget::finishedSlot_now);
      connect(m_NetManger_daily,&QNetworkAccessManager::finished,this,&WeatherWidget::finishedSlot_daily);
      connect(m_NetManger_life,&QNetworkAccessManager::finished,this,&WeatherWidget::finishedSlot_life);
      
      m_Reply_now = m_NetManger_now->get(QNetworkRequest(url_weather_now));
      m_Reply_life = m_NetManger_life->get(QNetworkRequest(url_weather_life));
      m_Reply_daily = m_NetManger_daily->get(QNetworkRequest(url_weather_daily));
      

      接着完成槽函数的编写,这里列举一个例子,其他的可以举一反三。

    • void WeatherWidget::finishedSlot_now(QNetworkReply *)
      {
          m_Reply_now->attribute(QNetworkRequest::HttpStatusCodeAttribute);
          m_Reply_now->attribute(QNetworkRequest::RedirectionTargetAttribute);
      
          if (m_Reply_now->error() == QNetworkReply::NoError)
          {
              QByteArray bytes = m_Reply_now->readAll();
              QString data = QString::fromUtf8(bytes);
              qDebug() << "m_Reply_now: " << data;
          }
          else
          {
              qDebug() << m_Reply_now->errorString();
          }
      
          m_Reply_now->deleteLater();
      }
      

      这时运行程序,可以看到qDebug()出来的东西,就是我们需要的JSON格式数据,但是还没有解析。那么接下来我们就来将这些数据从JSON格式中解析出来。

    • JSON格式的解析

    • QT5版本以后提供了JSON解析的库,我们可以直接通过QT进行调用。

      加入头文件

    • #include 
      #include 
      #include 
      #include 

      这里为了方便数据处理,自定义了三个结构体进行管理

    • struct Weather_Now_Data
      {
          QString last_update; //最后一次更新时间
          QString country; //国家
          QString id; //ID号
          QString name; //名字
          QString path; //地点
          QString timezone; //时区
          QString timezone_offset; //时区偏移
          QString code; //天气气象代码
          QString temperature; //温度
          QString text; //天气气象文字
      };
      
      struct Weather_Life_Data
      {
          QString car_washing; //洗车
          QString dressing; //穿衣
          QString flu; //感冒
          QString sport; //运动
          QString travel; //旅游
          QString uv; //紫外线
      };
      
      struct Weather_Daily_Data
      {
          QString date; //返回日期
          QString text_day; //白天天气现象文字
          QString code_day; //白天天气现象代码
          QString text_night; //晚间天气现象文字
          QString code_night; //晚间天气现象代码
          QString high; //当天最高温度
          QString low; //当天最低温度
          QString precip; //降水概率 范围0~100,单位百分比
          QString wind_direction; //风向文字
          QString wind_direction_degree; //风向角度 范围0~360
          QString wind_speed; //风速,单位km/h
          QString wind_scale; //风力等级
      };

      接着在.h文件中定义变量

      struct Weather_Now_Data weather_now;
      struct Weather_Daily_Data weather_daily_1, weather_daily_2, weather_daily_3;
      struct Weather_Life_Data weather_life;
      

      定义三个JSON格式解析函数

    • void json_analysis_now(QByteArray data);   //解析json格式现在天气
      void json_analysis_daliy(QByteArray data); //解析json格式逐日时间
      void json_analysis_life(QByteArray data);  //解析json格式生活指数
      

      解析JSON格式其实就是分解大括号和数组,下面我提供天气实况的解析代码,剩下的2个可以举一反三。你可以把我注释掉的qDebug()语句全部取消注释运行一次,然后看看输出结果,自己仔细研究一下就大概知道JSON格式是如何解析的了。

    • void WeatherWidget::json_analysis_now(QByteArray data)
      {
          QByteArray block;
          block = data;
          //qDebug() << "接收 : " << block;
          QJsonParseError json_error;
          QJsonDocument parse_doucment = QJsonDocument::fromJson(block, &json_error);
      
          //qDebug() << "parse_doucment : " << parse_doucment;
          //下面是json格式的解析
          if(json_error.error == QJsonParseError::NoError)
          {
              if(parse_doucment.isObject())
              {
                  //开始解析json对象
                  QJsonObject jsonObject = parse_doucment.object();
                  if(jsonObject.contains("results"))
                  {
                      QJsonValue results_value = jsonObject.take("results");
                      if(results_value.isArray()) //判断他是不是json数组
                      {
                          QJsonArray results_array = results_value.toArray();
                          QJsonObject results_object = results_array.at(0).toObject();
                          //qDebug() << "results_object : " << results_object;
      
                          //提取last_update
                          if(results_object.contains("last_update"))
                          {
                              weather_now.last_update = results_object.take("last_update").toString();
                              //qDebug() << "last_update : " << last_update;
                          }
      
                          //提取location
                          if(results_object.contains("location"))
                          {
                              QJsonValue location_value = results_object.take("location");
                              //qDebug() << "location_value : " << location_value;
                              QJsonObject location_object = location_value.toObject();
                              //提取country
                              if(location_object.contains("country"))
                              {
                                  weather_now.country = location_object.take("country").toString();
                                  //qDebug() << "country : " << country;
                              }
                              //提取id
                              if(location_object.contains("id"))
                              {
                                  weather_now.id = location_object.take("id").toString();
                                  //qDebug() << "id : " << id;
                              }
                              //提取name
                              if(location_object.contains("name"))
                              {
                                  weather_now.name = location_object.take("name").toString();
                                  //qDebug() << "name : " << name;
                              }
                              //提取path
                              if(location_object.contains("path"))
                              {
                                  weather_now.path = location_object.take("path").toString();
                                  //qDebug() << "path : " << path;
                              }
                              //提取timezone
                              if(location_object.contains("timezone"))
                              {
                                  weather_now.timezone = location_object.take("timezone").toString();
                                  //qDebug() << "timezone : " << timezone;
                              }
                              //提取timezone_offset
                              if(location_object.contains("timezone_offset"))
                              {
                                  weather_now.timezone_offset = location_object.take("timezone_offset").toString();
                                  //qDebug() << "timezone_offset : " << timezone_offset;
                              }
      
                          }
      
                          //提取now
                          if(results_object.contains("now"))
                          {
                              QJsonValue now_value = results_object.take("now");
                              //qDebug() << "now_value : " << now_value;
                              QJsonObject now_object = now_value.toObject();
                              //提取code
                              if(now_object.contains("code"))
                              {
                                  weather_now.code = now_object.take("code").toString();
                                  //qDebug() << "code : " << code;
                              }
                              //提取temperature
                              if(now_object.contains("temperature"))
                              {
                                  weather_now.temperature = now_object.take("temperature").toString();
                                  //qDebug() << "temperature : " << temperature;
                              }
                              //提取text
                              if(now_object.contains("text"))
                              {
                                  weather_now.text = now_object.take("text").toString();
                                  //qDebug() << "text : " << text;
                              }
      
                          }
                      }
                  }
              }
          }
      }
      

      将原来的qDebug()打印注释,换成JSON解析函数,然后刷新ui界面上的内容即可。

    • 解析代码有了,下面在槽函数中调用解析函数即可(二)通过网络获取天气信息_第9张图片

  • 补充一下

  • 如果在运行qt时报错

  • (二)通过网络获取天气信息_第10张图片

那么是qt的openssl库的问题,以下提供解决方案

如果是PC端

在安装目录

QT\MinGW\Tools\QtCreator\bin

找到libeay32.dll和ssleay32.dll链接库

  • 复制到QT\MinGW\5.6\mingw49_32\bin目录下,重新编译程序就可以解决

如果是ubuntu端

在安装目录下是找不到这两个库的,所以要重新编译openssl源码

去openssl的官网下载最新的openssl_1.0.2(似乎需要科学上网,也可以到我的github上下载)最好下载最新的版本,我试过1.0版本,但是并不能解决问题。

https://www.openssl.org/source/

(二)通过网络获取天气信息_第11张图片

下载好之后,放到ubuntu里,解压

tar –zxvf openssl-1.0.2r.tar.gz
cd openssl-1.0.2r

开始编译

./config enable-shared
make depend
make -j4

然后在当前目录生成4个.so的链接库

(二)通过网络获取天气信息_第12张图片

将这4个链接库,拷贝到qt的编译库下

/opt/Qt5.6.3/5.6.3/gcc_64/lib

然后重新编译运行程序就可以了

如果是ARM板,那么就需要交叉编译,注意修改交叉工具链,然后把生成的链接库拷贝到ARM板的/usr/lib目录下。

  • 测试

(二)通过网络获取天气信息_第13张图片

(二)通过网络获取天气信息_第14张图片

当然要保证板子能连上外网,才能成功获取数据。如图,测试成功。

Qt完整源码放在github上,有需要可以自行下载。 代码名称为190513.zip和190514.zip

https://github.com/ljy980330/opencv_face_sys

说明

190513.zip只有第一个测试图的界面,190514.zip加入了第二个界面的代码,触发方式为点击第一个界面的天气框内部的任意地方,进入第二个界面,在第二个界面点击屏幕任何区域都可以再次回到第一个界面。

下一章,讲解测试图1中右上角的系统信息如何获取。

 

有任何问题可以在下面给我留言!大家一起学习!

你可能感兴趣的:(qt+opencv人脸识别项目)