用Qt写爬虫爬https网站图片

前置技术:QT、爬虫基础、https(ssl证书)了解

爬虫是一种将网页上所需元素总结分类下载到本地的技术,它可以模拟人的操作爬取网页中的文字和图片,一般爬虫采用Python语言编写,不过Qt也是可以写爬虫的。
一般Qt的教学书籍中都会有下载http网页的例子,Qcreater中也有http案例代码,不过一般现在的网站都为https加密网站,爬取https网站需要加一步操作。

本案例为以下界面,可以实现下载https网站源代码并储存到文本文件中,通过正则表达式寻找源代码中所需要的的内容,通过URL批量下载目标图片。

用Qt写爬虫爬https网站图片
好,让我们开始。
 

1. 保证Qt可以对https网站进行操作


Qt默认是无法对https网站进行请求的,用请求http的方式下载https网站没有数据,在pro文件中添加 Qt += network,在初始程序中加入

 QNetworkAccessManager *manager = new QNetworkAccessManager(this);
 qDebug() << manager->supportedSchemes();

运行后会在输出界面显示
用Qt写爬虫爬https网站图片
没有https说明你的qt不能请求https网站

对此我们需要下载openSSL来实现qt对https的请求,openSSL的网站为http://slproweb.com/products/Win32OpenSSL.html
用Qt写爬虫爬https网站图片
下载对应的exe,注意要对应你的Qt的64/32位,下Light版本的就可以
安装时选择The OpenSSL binaries(/bin)directory
用Qt写爬虫爬https网站图片
安装完后在OpenSSL-Win64(32) / bin文件夹中找到以下两个文件
用Qt写爬虫爬https网站图片
也可以在我的下载文件中找到

将它们复制到qt执行后debug文件(有exe的那个文件)之后在运行会发现输出界面显示
用Qt写爬虫爬https网站图片
有了https,说明你的Qt已经可以请求https网站了,恭喜第一步完成。

2. 下载https网站源码并放到txt文件夹


用Qt写爬虫爬https网站图片
这一步分为得到源码和存入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


用Qt写爬虫爬https网站图片

该部分为读取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的执行代码在(),欢迎下载,我是曦泽周。

上一篇:【QT】简单的定时器例子


下一篇:qt 定时器事件QTimerEvent