前置技术:QT、爬虫基础、https(ssl证书)了解
爬虫是一种将网页上所需元素总结分类下载到本地的技术,它可以模拟人的操作爬取网页中的文字和图片,一般爬虫采用Python语言编写,不过Qt也是可以写爬虫的。
一般Qt的教学书籍中都会有下载http网页的例子,Qcreater中也有http案例代码,不过一般现在的网站都为https加密网站,爬取https网站需要加一步操作。
本案例为以下界面,可以实现下载https网站源代码并储存到文本文件中,通过正则表达式寻找源代码中所需要的的内容,通过URL批量下载目标图片。
好,让我们开始。
1. 保证Qt可以对https网站进行操作
Qt默认是无法对https网站进行请求的,用请求http的方式下载https网站没有数据,在pro文件中添加 Qt += network,在初始程序中加入
QNetworkAccessManager *manager = new QNetworkAccessManager(this); qDebug() << manager->supportedSchemes();
运行后会在输出界面显示
没有https说明你的qt不能请求https网站
对此我们需要下载openSSL来实现qt对https的请求,openSSL的网站为http://slproweb.com/products/Win32OpenSSL.html
下载对应的exe,注意要对应你的Qt的64/32位,下Light版本的就可以
安装时选择The OpenSSL binaries(/bin)directory
安装完后在OpenSSL-Win64(32) / bin文件夹中找到以下两个文件
也可以在我的下载文件中找到
将它们复制到qt执行后debug文件(有exe的那个文件)之后在运行会发现输出界面显示
有了https,说明你的Qt已经可以请求https网站了,恭喜第一步完成。
2. 下载https网站源码并放到txt文件夹
这一步分为得到源码和存入txt文件两部,我将代码写在一个按钮槽函数中
void Widget::on_btnOpenUrl_clicked()
{
//网页地址
const QString URLSTR =ui->lineEditURL->text();
//储存网页代码的文件
const QString FILE_NAME = ui->lineEditFileName->text();
QUrl url(URLSTR);
QNetworkAccessManager manager;
QEventLoop loop;
qDebug() << "Reading code form " << URLSTR;
//发出请求
QNetworkReply *reply = manager.get(QNetworkRequest(url));
//请求结束并下载完成后,退出子事件循环
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
//开启子事件循环
loop.exec();
//将读到的信息写入文件
code = reply->readAll();
QFile file(FILE_NAME);
file.open(QIODevice::WriteOnly);
QTextStream out(&file);
out << code << endl;
file.close();
qDebug() << "Finished, the code have written to " << FILE_NAME;
}
需要引用
#include <QUrl>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QNetworkAccessManager>
#include <QFile>
#include <QDebug>
好这下你可以在文件夹中得到code.txt文件了
3. 利用正则表达式提取所需要的内容或URL
该部分为读取txt中所下载的源代码,显示在旁边的textEdit中,利用正则表达式筛选出所需内容,append到下方的listWidget中,同时显示数量
代码写在一个按钮槽函数中
void Widget::on_btnGet_clicked()
{
//初始化
strl.clear();
ui->listWidget->clear();
//Qt读取txt文件
QString displayString;
QFile file("C:/Users/90546/Desktop/Qt/build-qtPaChong-Desktop_Qt_5_14_2_MinGW_64_bit-Debug/debug/code.txt");
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug()<<"Can't open the file!"<<endl;
}
QTextStream in(&file);
//采用GB2312编码
in.setCodec("GB2312");
while(!in.atEnd())
{
QString line=in.readLine()+'\n';
displayString.append(line);
}
ui->textEdit->clear();
//显示在textEdit中
ui->textEdit->setPlainText(displayString);
//正则表达式
QString sstr=ui->lineEditZhengZe->text();
QRegExp reg(sstr);
int u=0;
for(int pos=0;pos=reg.indexIn(displayString,pos),pos>=0; pos+=reg.matchedLength())
{
strl.append(reg.cap(0));
qDebug()<<pos; //返回查找到序号
qDebug()<<strl[u++];//返回匹配到的字串
}
//删除重复项
for (int i = 0; i < strl.size(); i++)
{
for (int k = i + 1; k < strl.size(); k++)
{
if ( strl[i] == strl[k])
{
strl.removeAt(k);
k--;
}
}
}
//添加listWidget
for(int i=0; i<strl.size();i++){
ui->listWidget->addItem(strl[i]);
}
if(strl.size()==0){
strl.append( "no date");
}
//将URL拼接后显示在下载的框中,显示数量
ui->lineEditUrlDownLoad->setText("https:"+strl[0]);
ui->labelNum->setNum(strl.size());
}
好,现在你有了想要下载的图片的URL
4.利用URL下载图片
这一部分我把功能分为了两块,一块为单次下载,通过点击下一连接切换目标URL,点击下载下载显示在文字框中的URL
下一连接按钮内容,用于切换下载lineEdit中的URL
void Widget::on_btnDownLoadFile_2_clicked()
{
static int i=0;
if(i< ui->labelNum->text().toInt()){
ui->lineEditUrlDownLoad->setText("https:"+strl[i++]);
}else{
QMessageBox::information(this, "last", "全部下载完毕!");
}
ui->labelNumLast->setNum(i);
}
点击下载内容,这一按钮比较传统,就是http下载,我也是在网上找的,包含一个InitGetRequest函数
void Widget::on_btnDownLoadFile_clicked()
{
//提取最后一个斜杠后内容作为下载的文件名
QString url=ui->lineEditUrlDownLoad->text();
int nindex= url.lastIndexOf('/'); //查找最后一个/
QString str=url.mid(nindex); //从最后一个/一直到字符串结尾
//保存的目标文件夹
QString strFilePath = "C:/Users/90546/Desktop/Qt/zZSearch Engine" +str ;
qDebug() << url ;
//建立file并写文件
QFile file;
file.setFileName(strFilePath);
if(file.open(QIODevice::WriteOnly))
{
QByteArray byte = Widget::InitGetRequest(url, "downImgFromUrl");
file.write(byte);
file.close();
}
}
//get
QByteArray Widget::InitGetRequest(QString url, QString obj)
{
//循环拼接
QString baseUrl =url;
//构造请求
QNetworkRequest request;
request.setUrl(QUrl(baseUrl));
QNetworkAccessManager *manager = new QNetworkAccessManager();
// 发送请求
QNetworkReply *pReplay = manager->get(request);
//开启一个局部的事件循环,等待响应结束,退出
QEventLoop eventLoop;
QObject::connect(pReplay,SIGNAL(finished()), &eventLoop, SLOT(quit()));
//add timeout deal
QTimer *tmpTimer = new QTimer();
connect(tmpTimer,SIGNAL(timeout()),&eventLoop, SLOT(quit()));
tmpTimer->setSingleShot(true);
tmpTimer->start(5000);
eventLoop.exec();
tmpTimer->stop();
if (pReplay->error() == QNetworkReply::NoError)
{
qInfo() << QString("request %1 NoError").arg(obj);
}
else
{
qWarning()<<QString("request %1 handle errors here").arg(obj);
QVariant statusCodeV = pReplay->attribute(QNetworkRequest::HttpStatusCodeAttribute);
//statusCodeV是HTTP服务器的相应码,reply->error()是Qt定义的错误码,可以参考QT的文档
qWarning()<<QString("request %1 found error ....code: %2 %3").arg(obj).arg(statusCodeV.toInt()).arg((int)pReplay->error());
qWarning(qPrintable(pReplay->errorString()));
}
//获取响应信息
QByteArray bytes = pReplay->readAll();
return bytes;
}
注意.h文件的声明
public:
QString code; //网页源代码
QByteArray InitGetRequest(QString url, QString obj);
QStringList strl;
至于自动下载我目前没啥用就不写了,你可以用Qtimer定时器依次调用下载的函数,就作为家庭作业交给你自己写了
恭喜我们一起写了个爬图片的爬虫,如果你想要其他的内容,学学正则表达式,改一下表达式那一栏的内容就行。
Qt的执行代码在(),欢迎下载,我是曦泽周。