新浪微博开放平台研究-实现微博自动评论(下)

源码下载


调用新浪微博开放接口,首先要到新浪服务器进行认证,新浪微博目前采用的是OAuth2.0认证,google了一下OAuth2.0认证过程大概如下:

1.待着你的应用app key去新浪服务器,新浪收到后会返回认证页面;

2.当用户授权给你的应用后,服务器 会返回一个code给你;

3.待着你的app key、app secret和服务器返回的code再去新浪服务器,服务器会返回一个access_token给你。

然后访问接口的时候记得待着这个access_token就行了。

不知道讲对了没有,目前我的程序的确就是这么做的。

其实新浪提供了很多本版的sdk,本文就不研究了,直接使用Qt自带的QNetworkAccessManager发送请求和接受应答。

在网上搜了一个qt的http请求帮助类,挺好用的,源码如下:

头文件:

#ifndef HTTPCLIENT_H
#define HTTPCLIENT_H

#include <QObject>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QEventLoop>
#include <QTimer>

class HttpClient : public QObject
{
    Q_OBJECT
public:
    explicit HttpClient(QObject *parent = 0);
    ~HttpClient();
    //http get请求
    QString get(QNetworkRequest& request);
    //http post请求
    QString post(QNetworkRequest& request, const QByteArray& data);
    //是否发生网络错误
    bool hasNetworkError(){ return this->m_hasNetworkError; }
    //获取网络连接错误代码
    int getNetworkErrorCode(){ return this->m_networkErrorCode; }
    //网络连接是否完成
    bool isHttpFinish(){ return this->m_isFinished; }
    //设置超时
    void setTimeOutLimit(int time);
signals:

public slots:
    //http请求完成
    void httpRequestFinished(QNetworkReply* reply);
    //请求超时处理
    void timeOutHandler();
    //网络错误处理
    void networkErrorHandler(QNetworkReply::NetworkError error);

private:
    QNetworkReply* m_pNetworkReply;
    QNetworkAccessManager *m_pNetworkMgr;
    bool m_hasNetworkError;//是否发生网络错误
    int m_networkErrorCode;//错误代码.如果发生网络错误,该值不为0
    QByteArray m_contentInByteArray;//请求到的内容
    QEventLoop* m_pEventLoop;//接受内容时保持响应
    volatile bool m_isFinished;
    QTimer* m_timer;//定时,用于超时检测
    int m_timeLimit;//用于设置超时

};

#endif // HTTPCLIENT_H
源文件:

#include "httpclient.h"
#include <QTextCodec>
#include <QDebug>

HttpClient::HttpClient(QObject *parent) :
    QObject(parent)
{
    this->m_contentInByteArray.clear();
    this->m_hasNetworkError = false;
    this->m_isFinished = false;
    this->m_networkErrorCode = QNetworkReply::NoError;
    this->m_pEventLoop = new QEventLoop(this);
    this->m_pNetworkMgr = new QNetworkAccessManager(this);
    this->m_pNetworkReply = NULL;
    this->m_timeLimit = 60*1000;
    this->m_timer = new QTimer(this);
    QObject::connect( this->m_pNetworkMgr, SIGNAL(finished(QNetworkReply*)), this, SLOT(httpRequestFinished(QNetworkReply*)));
    //QObject::connect( network, SIGNAL(finished(QNetworkReply*)), this, SIGNAL(finished()));
    QObject::connect( this->m_timer, SIGNAL(timeout()), this, SLOT(timeOutHandler()));
}
HttpClient::~HttpClient()
{
    delete this->m_pEventLoop;
    this->m_pEventLoop = NULL;
    delete this->m_pNetworkMgr;
    this->m_pNetworkMgr = NULL;
    delete this->m_timer;
    this->m_timer = NULL;
}
QString HttpClient::get(QNetworkRequest &request)
{
    this->m_pNetworkReply = this->m_pNetworkMgr->get(request);
    QObject::connect(this->m_pNetworkReply, SIGNAL(error(QNetworkReply::NetworkError)),
                     this, SLOT(networkErrorHandler(QNetworkReply::NetworkError)));
    //计时器启动
    this->m_timer->start(this->m_timeLimit);
    this->m_pEventLoop->exec();
    this->m_pNetworkReply->close();
    delete this->m_pNetworkReply;
    this->m_pNetworkReply = NULL;
    if(!this->hasNetworkError())
    {
        QTextCodec *codec = QTextCodec::codecForName("UTF-8");
        return codec->toUnicode(this->m_contentInByteArray);
    }
    else
    {
        return QString::null;
    }
}
QString HttpClient::post(QNetworkRequest &request, const QByteArray &data)
{
    this->m_pNetworkReply = this->m_pNetworkMgr->post(request,data);
    QObject::connect(this->m_pNetworkReply, SIGNAL(error(QNetworkReply::NetworkError)),
                     this, SLOT(networkErrorHandler(QNetworkReply::NetworkError)));
    //计时器启动
    this->m_timer->start(this->m_timeLimit);
    this->m_pEventLoop->exec();
    this->m_pNetworkReply->close();
    delete this->m_pNetworkReply;
    this->m_pNetworkReply = NULL;
    if(!this->hasNetworkError())
    {
        QTextCodec *codec = QTextCodec::codecForName("UTF-8");
        return codec->toUnicode(this->m_contentInByteArray);
    }
    else
    {
        return QString::null;
    }
}
void HttpClient::httpRequestFinished(QNetworkReply *reply)
{
    this->m_isFinished = true;
    this->m_contentInByteArray = reply->readAll();
    this->m_timer->stop();
    this->m_pEventLoop->exit();
}
void HttpClient::timeOutHandler()
{
    this->m_hasNetworkError = true;
    this->m_networkErrorCode = QNetworkReply::TimeoutError;
    this->m_contentInByteArray = this->m_pNetworkReply->readAll();
    this->m_timer->stop();
    this->m_pEventLoop->exit();
}
void HttpClient::networkErrorHandler(QNetworkReply::NetworkError error)
{
    this->m_hasNetworkError = true;
    this->m_networkErrorCode = error;
    qDebug()<<"网络错误描述:"<<this->m_pNetworkReply->errorString();
    qDebug()<<"网络错误代码:"<<this->m_pNetworkReply->error();
}
void HttpClient::setTimeOutLimit(int time)
{
    this->m_timeLimit = time;
}

微博接口返回的是json格式,意味着需要json解析,Qt自带一个QScriptEngine,可以用来解析简单的json,但貌似解析不了两层以上的json,没有仔细研究,先凑合着用:

QString JsonUtil::getValueByKey(const QString &source, const QString &key)
{
    QScriptEngine engine;
    QScriptValue sc = engine.evaluate("value = " + source);
    QScriptValueIterator it(sc);
    while(it.hasNext())
    {
        it.next();
        if (it.name().compare(key) == 0)

            return it.value().toString();

    }
    return NULL;
}

用到的工具类都准备好了,下面进入正题。

首先看入口程序:

#include "mainwindow.h"
#include <QApplication>
#include "oauthdialog.h"
#include <QTextCodec>
#include <QDebug>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QTextCodec *encoding = QTextCodec::codecForName("UTF-8");
    QTextCodec::setCodecForTr(encoding);
    QTextCodec::setCodecForLocale(encoding);
    QTextCodec::setCodecForCStrings(encoding);
    MainWindow w;
    OauthDialog dlg(&w);

    if(dlg.exec()==QDialog::Accepted)
    {
        QApplication::setQuitOnLastWindowClosed(true);

        w.show();
        return a.exec();
    }
    return 0;
}

MainWindow是主窗口类,QauthDialog是授权对话框,首先在授权对话框进行登录授权等。

#include "oauthdialog.h"
#include "ui_oauthdialog.h"
#include "httpclient.h"
#include "jsonutil.h"
#include <QUrl>
#include <QDebug>
#include <QMessageBox>
#include <mainwindow.h>

OauthDialog::OauthDialog(MainWindow* main) :
    main(main),
    ui(new Ui::OauthDialog)
{
    ui->setupUi(this);

    QUrl url;//登录授权地址
    url.setUrl("https://api.weibo.com/oauth2/authorize?client_id=yourid&redirect_uri=http://www.baidu.com&response_type=code");
    ui->m_webView->setUrl(url);
    //url变化信号,url发生变化判断是否是回调地址并截取code值
    QObject::connect( ui->m_webView, SIGNAL(urlChanged(QUrl)), this, SLOT(urlChgHandler(QUrl)) );

}

void OauthDialog::urlChgHandler(const QUrl& url)
{
    QString strUrl = url.toString();
    if (strUrl.contains("code="))
    {
        QStringList strList = strUrl.split("code=");
        QString code = strList.at(1);
        qDebug()<<"返回code值:"<<code;
        
        QString strAtUrl = "https://api.weibo.com/oauth2/access_token";
        QByteArray postData = "client_id=yourid&client_secret=yoursecret&grant_type=authorization_code&code=" + code.toAscii() +"&redirect_uri=http://www.baidu.com";
        HttpClient* http = new HttpClient();
        QUrl atUrl;
        atUrl.setUrl(strAtUrl);
        QNetworkRequest request;
        request.setUrl(atUrl);
        QString content = http->post(request,postData);
        delete http;
        //qDebug()<<"content:"<<content;
        JsonUtil json;
        QString accessToken = json.getValueByKey(content,"access_token");
        QString uid = json.getValueByKey(content,"uid");

        qDebug()<<"accessToken:"<<accessToken;
        qDebug()<<"uid:"<<uid;
        this->main->setAccesstoken(accessToken);
        this->main->setUid(uid);
        this->accept();
    }
}

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

上面代码获取到了access token,以后带着这个就可以访问其它接口了。

下面是获取登录用户的一些基本信息的接口:

void MainWindow::initAccountInfo()
{
    HttpClient *http = new HttpClient(this);
    QUrl url;
    url.setUrl("https://api.weibo.com/2/users/show.json");
    url.addQueryItem("access_token",this->getAccesstoken());
    url.addQueryItem("uid",this->getUid());
    QNetworkRequest request;
    request.setUrl(url);
    QString ret = http->get(request);
    JsonUtil json;
    this->ui->m_btn_name->setText(json.getValueByKey(ret,"screen_name"));
    this->ui->m_btn_attention->setText("关注:"+json.getValueByKey(ret,"friends_count"));
    this->ui->m_btn_funs->setText("粉丝:"+json.getValueByKey(ret,"followers_count"));
    this->ui->m_btn_weibo->setText("微博:"+json.getValueByKey(ret,"statuses_count"));
    delete http;
}

要想评论某条微博,首先要获取这个微博的id,试了一下获取指定用户的微博的api,不知道为什么返回来的是空,又试了一下获取指定用户的用户信息的接口,返回的内容正好包含用户最新的一条微博信息,正好用这个api做实验吧。

void MainWindow::getWeiboId()
{
    HttpClient *http = new HttpClient(this);
    QUrl url;
    url.setUrl("https://api.weibo.com/2/users/show.json");
    url.addQueryItem("access_token",this->getAccesstoken());
    url.addQueryItem("screen_name",this->ui->m_name->text());
    QNetworkRequest request;
    request.setUrl(url);
    QString ret = http->get(request);
    qDebug()<<ret;
    JsonUtil json;
    QString id = "id:\n"+json.getValueByKey(ret,"id")+"\n";
    QString name = "name:\n"+json.getValueByKey(ret,"screen_name")+"\n";
    QString description = "description:\n"+json.getValueByKey(ret,"description")+"\n";

    QStringList list = ret.split("idstr\":\"");
    QString temp = list.at(2);
    QStringList tempList = temp.split("\",\"text\":\"");
    QString weiboId = "weiboId:\n"+tempList.at(0)+"\n";
    QString weiboContent = "weiboContent:\n"+tempList.at(1).split("\",\"source\"").at(0)+"\n";

    this->ui->m_text_ids->setText(id+name+description+weiboId + weiboContent);
    delete http;
}

用户信息api返回的json信息包含两层,Qt自带的json解析类貌似解析不了,上面代码用QString的split硬生生的把想要的信息分隔了出来,网上有很多c++的开源json工具,这里就不搞那么复杂了。

下面是发表评论:

void MainWindow::timerUpdate()
{
    HttpClient *http = new HttpClient(this);
    QUrl url;
    url.setUrl("https://api.weibo.com/2/comments/create.json");
    QNetworkRequest request;
    request.setUrl(url);

    QString content = this->ui->m_comment->document()->toPlainText();
    QString weiboid = this->ui->m_weiboid->text();

    QByteArray data = "access_token="+this->getAccesstoken().toAscii()+
            "&comment="+QUrl::toPercentEncoding(content.toUtf8()) +
            "&id="+weiboid.toAscii();

    http->post(request,data);
    delete http;
}

用了QTimer定时器,按照指定频率执行timerUpdate函数。

这样就可以自动发表评论了。

看一下截图:




注:评论频率不要太高了,小心被啊浪封杀!而且对普通用户,每小时的api调用次数也是有限制的。


猜你喜欢

转载自blog.csdn.net/u012071890/article/details/17012531