说明:
本人没有看过爬虫相关的书籍,第一次写这种程序,这个程序只能实现简单网页图片抓取,原理很简单,没有学习过爬虫的朋友,也可做,适合学习,不适合拿去用。
程序思路大致如下:
1.下载要爬网站的页面数据,用QByteArray 对象存起来
2.处理数据,用正则表达式去扫描获得img标签下的src属性,并用容器保存属性
QRegularExpression regExp("<img[^>]*src=['\"]([^\"']*)['\"][^>]*>");
3.遍历,下载
上运行案列:
1. 运行起来,输入网页地址漂亮姐姐 - 高清图片,堆糖,美图壁纸兴趣社区 (duitang.com)https://www.duitang.com/album/?id=93121087&spm=2014.12553688.202.0,点击解析图片
2.提示下载成功
3.自动保存到该项目Debug目录中
详细介绍大致参考:
给定一个网站,自动爬取网页中的图片,下载保存到文件中
1.网络请求管理:通过QNetworkAccessManager类发起网络请求,实现了图片数据的异步下载。
2.图片下载:定义了downLoadImag函数,用于下载单张图片,并通过QImage::fromData将其转换为QImage对象。
3.错误处理:在za函数中,通过QNetworkReply::error信号捕获网络请求中的错误,并根据不同的错误类型进行处理。
4.多线程下载:在downLoadImags函数中,通过创建多个QNetworkAccessManager实例并发下载图片,提高了下载效率。
5.图片保存:在ondownLoadImags槽函数中,将下载的QImage转换为QPixmap并保存到本地文件。
6.HTML解析:在handleData函数中,使用正则表达式从HTML文本中提取图片URL,并将有效URL添加到下载列表。
7.用户界面交互:通过on_pushButton_clicked槽函数响应用户点击事件,执行图片下载和保存操作。
好了,准备工作
准备工作
1检查:
qDebug()<<QSslSocket::supportsSsl();//是否支持ssl
qDebug()<<QSslSocket::sslLibraryBuildVersionString();//依赖的ssl版本
如果不支持ssl,可以通过查找资料来解决这个问题,我的话提供下面方法
注意一点,如果程序提示:qt.network.ssl: QSslSocket::connectToHostEncrypted: TLS initialization failed ,解决办法是去QtCreator的安装目录,搜索ssleay32.dll和libeay32.dll,复制到程序运行目录
2.依赖
在开始之前,确保你已经安装了Qt,并且创建了一个Qt控制台应用程序项目。同时在运行程序之前,请确保已经在Qt项目的.pro文件中添加了网络访问模块的依赖
QT += network
源码:
dialog.h:
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include"QNetworkReply"
#include"QNetworkRequest"
namespace Ui {
class Dialog;
}
class QNetworkAccessManager;
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private slots:
void on_pushButton_clicked();
void ondownLoadImags();//下载保存槽函数
private:
QNetworkAccessManager*manager;//
QStringList urlList; //存储url
QString extractedDomain; //存https或http
bool exitMark; //退出标志
QList<QNetworkAccessManager*> mgrs;//manager容器
QStringList remainUrls;//剩余的url
private:
Ui::Dialog *ui;
void init();
QImage downLoadImag(const QString&modelUrl);//获取网页数据
void za(QString &modelUrl,QByteArray &data);//处理网页源代码
//多线程下载
void downLoadImags(const QStringList&urlLists);
void handleData(QByteArray&data);//处理网页源代码
void saveImg();//保存图片
void closeEvent(QCloseEvent *event);
};
#endif // DIALOG_H
dialog.cpp:
#include "dialog.h"
#include "ui_dialog.h"
#include"QDebug"
#include <QRegularExpression>
#include"QFileInfo"
#include"QByteArrayData"
#include<QMessageBox>
#include"qnetworkaccessmanager.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
init();
qDebug()<<QSslSocket::supportsSsl();//是否支持ssl
qDebug()<<QSslSocket::sslLibraryBuildVersionString();//依赖的ssl版本
exitMark=false;
}
Dialog::~Dialog()
{
delete ui;
// qDeleteAll(mgrs); //系统提供的方法
}
void Dialog::closeEvent(QCloseEvent *event)
{
QDialog::closeEvent(event);
exitMark=true;
foreach (QNetworkAccessManager*mgr, mgrs) {
mgr->deleteLater();
}
mgrs.clear();
}
void Dialog::init()
{
manager =new QNetworkAccessManager(this);
}
//单线程下载图片(没调用)
QImage Dialog::downLoadImag(const QString &modelUrl)
{
QUrl url(modelUrl);//构造网址
QNetworkRequest request;//请求
request.setUrl(url);//设置url
QNetworkReply * reply_ = manager->get(request);
QEventLoop eventLoop2;
connect(reply_, &QNetworkReply::finished, &eventLoop2, &QEventLoop::quit);
eventLoop2.exec(QEventLoop::ExcludeUserInputEvents);
QByteArray data = reply_->readAll();
QImage imag=QImage::fromData(data);
reply_->deleteLater();
return imag;
}
//获取网站数据
void Dialog::za(QString &modelUrl, QByteArray &data)
{
QUrl url(modelUrl);//构造网址
QNetworkRequest request;//请求
request.setUrl(url);//设置url
QNetworkReply * reply_ = manager->get(request);//自动产生线程
connect(reply_, &QNetworkReply::finished, this, [&]() {
if (reply_->error() == QNetworkReply::NoError) {
// 请求成功,URL是有效的
qDebug() << "URL is valid.";
} else {
// 请求失败,URL可能不可用
qDebug() << "URL is invalid or cannot be accessed.";
QMessageBox::warning(this,"提示","请求失败,URL可能不可用");
}
// reply_->deleteLater();
});
connect(reply_, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error),[&](QNetworkReply::NetworkError code)
{
switch(static_cast<int>(code))
{
case QNetworkReply::ConnectionRefusedError:
qDebug() << "远程服务器拒绝连接(服务器不接受请求)";
break;
case QNetworkReply::HostNotFoundError:
qDebug() << "找不到远程主机名(无效的主机名)";
break;
case QNetworkReply::TimeoutError:
qDebug() << "与远程服务器的连接超时";
break;
default:
break;
}
});
QEventLoop eventLoop2;
connect(reply_, &QNetworkReply::finished, &eventLoop2, &QEventLoop::quit);
eventLoop2.exec(QEventLoop::ExcludeUserInputEvents);
data = reply_->readAll();
reply_->deleteLater();
}
//多线程下载图片
void Dialog::downLoadImags(const QStringList &urlLists)
{
foreach (const QString &url,urlLists)
{
if(mgrs.count()>10)//一次最多只能个图片同时下载
{
remainUrls<<url;
continue;//跳过本次循环
}
QNetworkAccessManager *mgr =new QNetworkAccessManager();
mgrs<<mgr;//移入
QNetworkRequest request;
request.setUrl(url);
QNetworkReply * reply = mgr->get(request);//自动产生新线程
connect(reply,&QNetworkReply::finished,this,&Dialog::ondownLoadImags);
}
}
//保存图片槽函数
void Dialog::ondownLoadImags()
{
QObject *obj =this->sender(); //sender方法获取replay
QNetworkReply *reply =qobject_cast<QNetworkReply*>(obj);
if(reply==NULL)
return;
QByteArray data= reply->readAll();
QNetworkAccessManager *mgr =reply->manager();
mgrs.removeAll(mgr);
mgr->deleteLater(); //延后删除
QImage imag = QImage::fromData(data);
QFileInfo info(reply->url().toString());// 转换!!!!
QString fileName =info.fileName();
// 保存QImage到指定路
bool success = imag.save(fileName); // 第二个参数是文件格式,第三个参数是质量,-1代表默认质量
if (success) {
qDebug()<<fileName<< "Image saved successfully.";
} else {
qDebug() << "Failed to save image.";
}
if(exitMark)//判断是否关闭窗口
return;
if(remainUrls.isEmpty())//判断剩余下载是否为空
return;
QStringList listone;
listone<<remainUrls.takeFirst();
downLoadImags(listone);//调用剩余的未下载的,一次只能推一个
}
//在downLoadImags函数中,通过创建多个QNetworkAccessManager实例并发下载图片
void Dialog::handleData(QByteArray & data)
{
QString str = QString(data);
// qDebug() << endl << endl << endl << str;
QRegularExpression regExp("<img[^>]*src=['\"]([^\"']*)['\"][^>]*>");
QStringList list = str.split("\n");
urlList.clear();
for (int i = 0; i < list.size(); ++i) {
int pos = 0;
while (true) {
QRegularExpressionMatch match = regExp.match(list.at(i), pos);
if (!match.hasMatch()) break;
pos = match.capturedEnd();
qDebug() << "pos :" << pos;
QString url=match.captured(1);//捕获值为1
if (url.contains("http")) {//简单判断src属性
// URL是有效的
QString valuedUrl=match.captured(1);
qDebug() << "Match1: " << match.captured(1);
urlList <<valuedUrl;
}
else {
// URL是无效的 相对路径
QString valuedUrl=extractedDomain+match.captured(1);
qDebug() << "Match2: " << valuedUrl;
urlList <<valuedUrl;
QString valuedUrl2 ="https:"+match.captured(1);
qDebug() << "Match3: " << valuedUrl2;
urlList <<valuedUrl2;
}
}
}
}
//保存图片
void Dialog::saveImg()
{
foreach (const QString& url, urlList)
{
QImage imag=downLoadImag(url);
QPixmap zzz=QPixmap::fromImage(imag);
// QIcon zz(zzz);
// ui->toolButton->setIcon(zz);
// ui->toolButton->setIconSize(QSize(ui->toolButton->size()));
QFileInfo info(url);
QString fileName =info.fileName();
// 保存QImage到指定路
bool success = zzz.save(fileName); // 第二个参数是文件格式,第三个参数是质量,-1代表默认质量
if (success) {
qDebug()<<fileName<< "Image saved successfully.";
} else {
qDebug() << "Failed to save image.";
}
}
}
void Dialog::on_pushButton_clicked()
{
//获取网页数据
QByteArray data;
QString text=ui->lineEdit->text();
QRegularExpression regex("^https?://[^/]+");//表达式用于匹配以http://或https://开头的头部
QString inputUrl = text;
QRegularExpressionMatch match = regex.match(inputUrl);
if (match.hasMatch()) {
extractedDomain = match.captured(0);
}
za(text,data);//识别网站,返回
handleData(data);//处理数据
ui->textEdit->clear();
ui->textEdit_2->clear();
// ui->textEdit->setText(data.constData());//加载网页到ui上
for(int i=0;i<urlList.size();i++)
{
ui->textEdit_2->append(urlList[i]);
}
//saveImg(); 单线程
downLoadImags(urlList);//保存数据 多线程
}
ui: