天天看點

Qt5擷取并解析中國天氣網資料

天氣查詢 API 接口

中國天氣網提供 3 個 API 接口,以北京為例:

http://m.weather.com.cn/data/101010100.html
http://weather.com.cn/data/sk/101010100.html
http://weather.com.cn/data/cityinfo/101010100.html      

直接通路這 3 個 Web API 即可傳回對應城市的天氣資訊,傳回的是 JSON 格式資料。(第一個通路不了 -’’-)

後面的數字是城市代碼,如果想查詢其他城市的天氣情況,隻需要更換為對應的城市代碼即可。那怎麼知道城市代碼呢?我這裡有一份​​中國天氣網城市代碼文檔​​​。城市代碼由 9 位數字組成,按照長度可以分為如下四個部分:

比如,北京市海澱區是 101010200,廣州是 101280101,台北是 101340101。

http://weather.com.cn/data/sk/101010100.html 傳回的 JSON 資料:

{
    "weatherinfo":
    {
        "city":"北京",
        "cityid":"101010100",
        "temp":"27.9",
        "WD":"南風",
        "WS":"小于3級",
        "SD":"28%",
        "AP":"1002hPa",
        "njd":"暫無實況",
        "WSE":"<3",
        "time":"17:55",
        "sm":"2.1",
        "isRadar":"1",
        "Radar":"JC_RADAR_AZ9010_JB"
    }
}      

http://weather.com.cn/data/cityinfo/101010100.html 傳回的 JSON 資料:

{
    "weatherinfo":
    {
        "city":"北京",
        "cityid":"101010100",
        "temp1":"18℃",
        "temp2":"31℃",
        "weather":"多雲轉陰",
        "img1":"n1.gif",
        "img2":"d2.gif",
        "ptime":"18:00"
    }
}      

請求與響應

為友善起見,我們設定一個輸入框擷取城市代碼,設定一個按鈕觸發查詢請求,然後将實時氣溫顯示在下面。

Qt5擷取并解析中國天氣網資料

Show the code !

【頭檔案】

#ifndef
#define

#include <QWidget>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>

namespace Ui {
class MainWidget;
}

class MainWidget : public QWidget
{
    Q_OBJECT

public:
    explicit MainWidget(QWidget *parent = 0);
    ~MainWidget();

private slots:
    void slotReadyRead();
    void downloadFinished();
    void replyFinished(QNetworkReply *reply);

    void on_pushButton_clicked();

private:
    Ui::MainWidget *ui;

    QNetworkAccessManager *manager;
    QNetworkReply *reply;
};

#endif// MAINWIDGET_H      

【源檔案】

#include "mainwidget.h"
#include "ui_mainwidget.h"

#include <QTextCodec>

MainWidget::MainWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainWidget)
{
    ui->setupUi(this);
    this->setWindowTitle(tr("天氣查詢"));

    manager = new QNetworkAccessManager(this);
    connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
}

MainWidget::~MainWidget()
{
    delete ui;
}

void MainWidget::on_pushButton_clicked()
{
    qDebug() << "clicked";

    QNetworkRequest request;
    request.setUrl(QUrl(QString("http://weather.com.cn/data/sk/%1.html").arg(ui->lineEdit->text())));

    /* Set header */
    request.setRawHeader(QByteArray("User-Agent"), QByteArray("Mozilla/5.0"));
    /* Auto redirect */
    request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);

    reply = manager->get(request);
    connect(reply, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));
    connect(reply, SIGNAL(finished()), this, SLOT(downloadFinished()));
}

void MainWidget::slotReadyRead()
{
    qDebug() << "ready";
}

void MainWidget::downloadFinished()
{
    qDebug() << "download";
    reply->deleteLater();
}

void MainWidget::replyFinished(QNetworkReply *reply)
{
    qDebug() << "reply";

    /* Get http status code */
    QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
    if(statusCode.isValid()) {
        qDebug() << "status code:" << statusCode.toInt();
    }

    QVariant reason = reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute);
    if(reason.isValid()) {
        qDebug() << "reason:" << reason.toString();
    }

    QNetworkReply::NetworkError err = reply->error();
    if(err != QNetworkReply::NoError) {
        qDebug() << "Failed:" << reply->errorString();
    }
    else {
        QByteArray bytes = reply->readAll();
        QString string = QString::fromUtf8(bytes);
        qDebug() << string;
    }
}      

輸入 ​

​101010100​

​,點選查詢按鈕,可以看到終端列印如下:

Qt5擷取并解析中國天氣網資料

需要特别注意的是,由于請求發生重定向,是以一定要加上這行代碼,設定自動跳轉,否則會傳回 302。

/* Auto redirect */
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);      

解析 JSON 資料

建立函數 parseFromJson 用于讀取、解析 JSON 資料,并在 TextBrowser 中直接顯示出來。

void parseFromJson(const QString &jsonStr);      

具體代碼實作如下:

void MainWidget::parseFromJson(const QString &jsonStr)
{
    QJsonParseError err;
    QJsonDocument doc = QJsonDocument::fromJson(jsonStr.toUtf8(), &err);

    if(err.error != QJsonParseError::NoError) {
        qDebug() << "Parsed error";
        return;
    }
    QJsonObject obj = doc.object();
    if(obj.contains(QLatin1Literal("weatherinfo"))) {
        qDebug() << "Parsing";
        QJsonObject subObj = obj.value("weatherinfo").toObject();
        QString city = subObj["city"].toString();
        QString temp = subObj["temp"].toString();
        QString WD = subObj["WD"].toString();
        QString WS = subObj["WS"].toString();
        QString time = subObj["time"].toString();
        ui->textBrowser->setText(QString("城市:%1\n氣溫:%2\n風向:%3\n風速:%4\n時間:%5").arg(city).arg(temp).arg(WD).arg(WS).arg(time));
    }
}      

運作程式,輸入城市代碼,查詢… 如下:

Qt5擷取并解析中國天氣網資料