您的位置:首页 > 编程语言 > Qt开发

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

2013-11-28 22:44 453 查看
源码下载

调用新浪微博开放接口,首先要到新浪服务器进行认证,新浪微博目前采用的是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调用次数也是有限制的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息