摘要:本人希望能够每天更换桌面背景,又觉得常规手动步骤太过麻烦(从网上找图片->下载至本地->打开本地路径->右键设为壁纸),鉴于必应壁纸质量很高,索性写了一个程序自动实现其全部过程。(文末附本程序完整源代码的链接)
本文介绍从网上爬取图片的实现,即Qt的http网络通讯的简单应用。后半部分调用本地系统API设置壁纸过程在其他文章另有介绍。
****本人亲测平台包含****: Win10,Ubuntu16.04LTS
****运行环境****:Qt5.7.0
第一次Get
通过QNetworkAccessManager类的get函数,爬下Bing主页全部源码至本地的一个txt文件中,便于后续的分析处理。小贴士:用QNetworkRequest类的setUrl函数设定url。
QNetworkAccessManager manager;//要用到connect,所以在头文件中提前声明此对象
void WallPaper::getWholeWebSource()
{
showStatusTips(PICTURE_DOWNLOADING);//一个用于显示当前状态的函数,详见文末链接程序github源码
QUrl url("http://cn.bing.com/");
QNetworkRequest request;
request.setUrl(url);
//将完成信号与我自定义的槽函数findPicUrl相连,用finished信号传递reply信息至槽函数中
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(findPicUrl(QNetworkReply*)));
//在连接了信号与槽之后,就可以进行get操作。get一旦完成,会自动触发finished信号,从而转至槽函数
manager.get(request);
}
bing主页的源码分析
一旦对应第一步当中的get的finished信号被触发,则转至该槽函数findPicUrl,同时传递过来一个对象QNetworkReply *reply
。通过reply->readAll()
读取get到的内容
分析源码,会发现壁纸URL并不完整,只是一个片段,尚无法通过它获取壁纸图片,需要自己再稍微拼接一下。因此,具体步骤为:1.通过一定的算法找到此片段;2.截取之;3.与http://cn.bing.com/拼接
void WallPaper::findPicUrl(QNetworkReply *reply)
{
disconnect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(findPicUrl(QNetworkReply*)));
if(reply->error() == QNetworkReply::NoError)
{
QByteArray webContent = reply->readAll();
QFile file("测试文件.txt");//写成一个可阅读的txt文档,用于程序测试
file.open(QIODevice::ReadWrite);
file.write(webContent);
file.close();
QByteArray targetUrl = "/az/hprichbg/rb/";//目标url片段,通过它抓取到完整的壁纸网址
int indexStart = -1;
int indexEnd = -1;
indexStart = webContent.indexOf(targetUrl);
if(indexStart != -1)//若在获取到的网页源码中找到了所需url,则get之
{
qDebug("找到了壁纸的url:");
webContent = webContent.mid(indexStart);//截取右侧
indexEnd = webContent.indexOf("jpg");
indexEnd = indexEnd + 2;
QUrl url("http://cn.bing.com" + webContent.left(indexEnd + 1));//继续截取并拼接
qDebug()<<url;
emit urlFound(url);//发射了一个信号
}
else
showStatusTips(URL_NOT_FOUND);//一个用于显示当前状态的函数,详见文末链接程序github源码
}
else
showStatusTips(NETWORK_CONNECTION_FAILED, reply->errorString());
}
上文中你发现,由于findPicUrl函数也发射了一个信号,urlFound(url),因此在构造函数处加一个connect
//当最终计算出壁纸的目标url后,则转至downloadPic函数,正式开始下载壁纸
connect(this, SIGNAL(urlFound(QUrl)), this, SLOT(downloadPic(QUrl)));
第二次Get
当urlFound信号发射后,转至downloadPic函数,get的用法与前文一致
void WallPaper::downloadPic(QUrl url)
{
QNetworkRequest request;
request.setUrl(url);
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(savePic(QNetworkReply*)));
manager.get(request);//用finished信号传递reply
}
IO操作,保存至本地
当返回信号finished时,将bing返回的reply信息,即图片,保存至本地
void WallPaper::savePic(QNetworkReply *reply)
{
disconnect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(savePic(QNetworkReply*)));
if(reply->error() == QNetworkReply::NoError)
{
QPixmap picture;
//读取IO信息
QByteArray picData = reply->readAll();
if(!picture.loadFromData(picData, "JPG"))//用QPixmap定义的对象picture,读取从bing网站传过来的数据,格式为jpg的图片
{
showStatusTips(LOAD_FROM_DATA_FAILED, QString("%1").arg(picData.size()));
return;
}
//定义保存路径filepath
filePath = QDir::homePath() + "/" + "Pictures/";
QDir dir;
dir.mkdir(filePath);
filePath += QDateTime::currentDateTime().toString("yyyy-MM-dd") + "_Bing_txmy.jpg";
//save函数保存至本地
if(!picture.save(filePath))
{
qDebug()<<"图片保存失败!";
}
else
{//软件其他操作
showStatusTips(WALLPAPER_READY);
showStatusTips(COUNT_DOWN_TO_CLOSE);
emit picSaved(filePath);
DataCenter &dc = DataCenter::getInstance();
QStringList paths = dc.getPicFilePaths();
int index = paths.indexOf(filePath);
if(index != -1)
dc.setCurrentIndex(index);
}
}
else
showStatusTips(DOWNLOAD_FAILED, reply->errorString());
}
Github源代码:
一款简约的壁纸设置程序 https://github.com/polarbear0330/DeskWallPaper