首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Qt | http获取网页文件(小项目)

Qt | http获取网页文件(小项目)

原创
作者头像
Qt历险记
发布2024-10-23 21:07:54
发布2024-10-23 21:07:54
8770
举报
文章被收录于专栏:Qt6 研发工程师Qt6 研发工程师

点击上方"蓝字"关注我们

ctrl+r 运行 URL可以自己替换一个试一试

【源码获取】

链接:https://pan.baidu.com/s/1QzHKZPXjkpx2p5TWUS_acA?pwd=5xsd 

提取码:5xsd 

01、QProgressDialog

>>>QProgressDialog 是 Qt 框架中的一个类,主要用于显示一个进度对话框,通常用在执行长时间操作时,以便让用户了解当前操作的进度。它可以用来进行反馈,显示任务的完成情况。

02、QNetworkAccessManager

>>>QNetworkAccessManager 是 Qt 框架中的一个类,主要用于处理网络请求,包括发送和接收数据。它提供了一个高级的接口来执行 HTTP、HTTPS 和 FTP 等协议的网络操作。

03、QUrl

>>>QUrl 是 Qt 框架中的一个类,用于表示和处理 URL(统一资源定位符)。它提供了一种便捷的方式来解析和构造 URL,以及进行相关的操作。

04、memory

>>><memory> 是 C++ 标准库中的一个头文件,主要提供智能指针和内存管理的功能。它的引入旨在简化内存管理,减少内存泄漏的风险,并提高代码的安全性和可维护性。

05、QNetworkReply

>>>QNetworkReply 是 Qt 框架中的一个类,用于处理网络请求的响应。它与 QNetworkAccessManager 一起使用,用于接收来自网络服务的异步响应数据。

06、QSslError

>>>QSslError 是 Qt 框架中的一个类,主要用于表示与 SSL(安全套接字层)相关的错误。它通常在使用 QSslSocket 或 QNetworkReply 进行安全网络通信时被用到。

07、QAuthenticator

>>>QAuthenticator 是 Qt 框架中的一个类,用于处理网络认证过程中的用户身份验证信息。它主要与 QNetworkAccessManager 和 QNetworkReply 类一起使用,以便在进行 HTTP 认证时,提供必需的用户名和密码。

08、http.pro

>>>

代码语言:javascript
复制
QT += network widgets    # 添加网络模块和小部件模块到项目中,以便使用它们提供的功能​HEADERS += httpwindow.h   # 将 httpwindow.h 文件添加到头文件列表中SOURCES += httpwindow.cpp \  # 将 httpwindow.cpp 文件添加到源文件列表中           main.cpp       # 将 main.cpp 文件添加到源文件列表中FORMS += authenticationdialog.ui  # 将 authenticationdialog.ui 文件添加到表单文件列表中​# installtarget.path = $$[QT_INSTALL_EXAMPLES]/network/http  # 设置安装目标路径为 Qt 示例目录下的 network/httpINSTALLS += target   # 添加安装目标到 INSTALLS 列表中​DISTFILES += \      # 指定要分发的文件列表    CMakeLists.txt  # 添加 CMakeLists.txt 文件到分发文件中​

09、httpwindow.h

>>>#include <QProgressDialog> // 用于显示下载进度的对话框 #include <QNetworkAccessManager> // 处理网络请求的核心类 #include <QUrl> #include <memory> // 使用智能指针管理资源

代码语言:javascript
复制
#ifndef HTTPWINDOW_H#define HTTPWINDOW_H​#include <QProgressDialog> // 用于显示下载进度的对话框#include <QNetworkAccessManager> // 处理网络请求的核心类#include <QUrl>​#include <memory> // 使用智能指针管理资源​// 前向声明:声明了一些Qt类,以便在代码中使用,避免包含不必要的头文件QT_BEGIN_NAMESPACEclass QFile;class QLabel;class QLineEdit;class QPushButton;class QSslError;class QAuthenticator;class QNetworkReply;class QCheckBox;#if QT_CONFIG(networkproxy) // 检查Qt库是否启用了网络代理class QNetworkProxy;#endif​QT_END_NAMESPACE​// 进度对话框类class ProgressDialog : public QProgressDialog {    Q_OBJECT​public:    explicit ProgressDialog(const QUrl &url, QWidget *parent = nullptr);​public slots:   void networkReplyProgress(qint64 bytesRead, qint64 totalBytes);};​// 登录框类class HttpWindow : public QDialog{    Q_OBJECT​public:    explicit HttpWindow(QWidget *parent = nullptr);    ~HttpWindow();​    void startRequest(const QUrl &requestedUrl);​private slots:    void downloadFile();    void cancelDownload();    void httpFinished();    void httpReadyRead();    void enableDownloadButton();    void slotAuthenticationRequired(QNetworkReply *, QAuthenticator *authenticator);#if QT_CONFIG(ssl)    void sslErrors(const QList<QSslError> &errors);#endif#if QT_CONFIG(networkproxy)    void slotProxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator);#endif​private:    std::unique_ptr<QFile> openFileForWrite(const QString &fileName);​    QLabel *statusLabel;    QLineEdit *urlLineEdit;    QPushButton *downloadButton;    QCheckBox *launchCheckBox;    QLineEdit *defaultFileLineEdit;    QLineEdit *downloadDirectoryLineEdit;​    QUrl url;    QNetworkAccessManager netAccessManager;    QScopedPointer<QNetworkReply, QScopedPointerDeleteLater> reply;    std::unique_ptr<QFile> file;    bool httpRequestAborted = false;};​#endif​

10、httpwindow.cpp

>>>#include <QtWidgets>     // 引入 QtWidgets 模块,提供创建图形用户界面 (GUI) 的类和功能 #include <QtNetwork>     // 引入 QtNetwork 模块,提供网络编程相关的类和功能 #include <QUrl>          // 引入 QUrl 类,用于处理 URL(统一资源定位符) #include <algorithm>     // 引入标准算法库,提供常用的算法功能,如排序、查找等 #include <memory>        // 引入内存管理库,提供智能指针等内存管理工具

代码语言:javascript
复制
/*
* 提示:该行代码过长,系统自动注释不进行高亮。一键复制会移除系统注释 
* // 包含头文件#include "httpwindow.h"#include "ui_authenticationdialog.h"​#include <QtWidgets>#include <QtNetwork>#include <QUrl>​#include <algorithm>#include <memory>​// 判断是否配置了SSL#if QT_CONFIG(ssl)const char defaultUrl[] = "https://www.qt.io/"; // SSL连接时的默认URL#elseconst char defaultUrl[] = "http://www.qt.io/"; // 非SSL连接时的默认URL#endifconst char defaultFileName[] = "index.html"; // 默认文件名​// 进度对话框构造函数ProgressDialog::ProgressDialog(const QUrl &url, QWidget *parent)  : QProgressDialog(parent){    setWindowTitle(tr("下载进度")); // 设置窗口标题    setLabelText(tr("下载中... %1.").arg(url.toDisplayString())); // 设置标签文本    setMinimum(0); // 设置最小值    setValue(0); // 设置当前值    setMinimumDuration(0); // 设置最小持续时间    setMinimumSize(QSize(400, 75)); // 设置最小窗口大小}​// 更新下载进度void ProgressDialog::networkReplyProgress(qint64 bytesRead, qint64 totalBytes){    setMaximum(totalBytes); // 设置最大值为总字节数    setValue(bytesRead); // 设置当前值为已读取的字节数}​// HTTP窗口构造函数HttpWindow::HttpWindow(QWidget *parent)    : QDialog(parent)    , statusLabel(new QLabel(tr("请输入要下载的文件的URL.\n\n"), this)) // 状态标签    , urlLineEdit(new QLineEdit(defaultUrl)) // URL输入框    , downloadButton(new QPushButton(tr("下载"))) // 下载按钮    , launchCheckBox(new QCheckBox(tr("启动文件"))) // 启动文件复选框    , defaultFileLineEdit(new QLineEdit(defaultFileName)) // 默认文件名输入框    , downloadDirectoryLineEdit(new QLineEdit) // 下载目录输入框{    setWindowTitle(tr("HTTP Client")); // 设置窗口标题​    // 连接认证请求信号与槽    connect(&netAccessManager, &QNetworkAccessManager::authenticationRequired,            this, &HttpWindow::slotAuthenticationRequired);​#if QT_CONFIG(networkproxy)    // 连接代理认证请求信号与槽    connect(&netAccessManager, &QNetworkAccessManager::proxyAuthenticationRequired,            this, &HttpWindow::slotProxyAuthenticationRequired);#endif​    QFormLayout *formLayout = new QFormLayout; // 创建表单布局    urlLineEdit->setClearButtonEnabled(true); // 启用清除按钮    connect(urlLineEdit, &QLineEdit::textChanged, this, &HttpWindow::enableDownloadButton); // 连接文本变化信号与槽    formLayout->addRow(tr("&URL:"), urlLineEdit); // 添加URL输入框到布局​    // 获取下载目录    QString downloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);    if (downloadDirectory.isEmpty() || !QFileInfo(downloadDirectory).isDir())        downloadDirectory = QDir::currentPath(); // 如果为空则使用当前路径    downloadDirectoryLineEdit->setText(QDir::toNativeSeparators(downloadDirectory)); // 设置下载目录文本框    formLayout->addRow(tr("&Download directory:"), downloadDirectoryLineEdit); // 添加下载目录到布局    formLayout->addRow(tr("Default &file:"), defaultFileLineEdit); // 添加默认文件名到布局    launchCheckBox->setChecked(true); // 默认勾选启动文件复选框    formLayout->addRow(launchCheckBox); // 添加复选框到布局​    QVBoxLayout *mainLayout = new QVBoxLayout(this); // 创建主布局    mainLayout->addLayout(formLayout); // 添加表单布局到主布局​    mainLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding)); // 添加空白项以扩展布局​    statusLabel->setWordWrap(true); // 启用换行    mainLayout->addWidget(statusLabel); // 添加状态标签到主布局​    downloadButton->setDefault(true); // 设置下载按钮为默认按钮    connect(downloadButton, &QAbstractButton::clicked, this, &HttpWindow::downloadFile); // 连接下载按钮点击信号与槽    QPushButton *quitButton = new QPushButton(tr("Quit")); // 创建退出按钮    quitButton->setAutoDefault(false); // 设置不为默认按钮    connect(quitButton, &QAbstractButton::clicked, this, &QWidget::close); // 连接退出按钮点击信号与槽    QDialogButtonBox *buttonBox = new QDialogButtonBox; // 创建对话框按钮框    buttonBox->addButton(downloadButton, QDialogButtonBox::ActionRole); // 添加下载按钮    buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole); // 添加退出按钮    mainLayout->addWidget(buttonBox); // 添加按钮框到主布局​    urlLineEdit->setFocus(); // 设置URL输入框为焦点}​// HttpWindow析构函数HttpWindow::~HttpWindow() = default;​// 启动请求void HttpWindow::startRequest(const QUrl &requestedUrl){    qDebug() << "HttpWindow::startRequest requestedUrl = " << requestedUrl.toDisplayString();​    url = requestedUrl; // 设置请求的URL    httpRequestAborted = false; // 重置请求中止标志​    reply.reset(netAccessManager.get(QNetworkRequest(url))); // 发送GET请求并保存响应    // 连接请求完成信号与槽    connect(reply.get(), &QNetworkReply::finished, this, &HttpWindow::httpFinished);    // 连接有数据可读信号与槽    connect(reply.get(), &QIODevice::readyRead, this, &HttpWindow::httpReadyRead);#if QT_CONFIG(ssl)    // 连接SSL错误信号与槽    connect(reply.get(), &QNetworkReply::sslErrors, this, &HttpWindow::sslErrors);#endif​    ProgressDialog *progressDialog = new ProgressDialog(url, this); // 创建进度对话框    progressDialog->setAttribute(Qt::WA_DeleteOnClose); // 关闭时删除对话框    connect(progressDialog, &QProgressDialog::canceled, this, &HttpWindow::cancelDownload); // 连接取消信号与槽    connect(reply.get(), &QNetworkReply::downloadProgress,            progressDialog, &ProgressDialog::networkReplyProgress); // 连接下载进度信号与槽    connect(reply.get(), &QNetworkReply::finished, progressDialog, &ProgressDialog::hide); // 连接请求完成信号与槽    progressDialog->show(); // 显示进度对话框​    statusLabel->setText(tr("下载 %1...").arg(url.toString())); // 显示下载状态}​// 下载文件void HttpWindow::downloadFile(){    const QString urlSpec = urlLineEdit->text().trimmed(); // 获取URL文本    if (urlSpec.isEmpty())        return; // 如果为空则返回​    const QUrl newUrl = QUrl::fromUserInput(urlSpec); // 创建URL对象    if (!newUrl.isValid()) { // 验证URL有效性        QMessageBox::information(this, tr("错误"),                                 tr("无效 URL: %1: %2").arg(urlSpec, newUrl.errorString())); // 显示错误信息        return;    }​    QString fileName = newUrl.fileName(); // 获取文件名    qDebug() << "HttpWindow::downloadFile fileName = " << fileName << endl;​    if (fileName.isEmpty())        fileName = defaultFileLineEdit->text().trimmed(); // 如果文件名为空则使用默认文件名    if (fileName.isEmpty())        fileName = defaultFileName; // 如果仍为空则使用硬编码默认文件名    QString downloadDirectory = QDir::cleanPath(downloadDirectoryLineEdit->text().trimmed()); // 清理下载目录路径    bool useDirectory = !downloadDirectory.isEmpty() && QFileInfo(downloadDirectory).isDir(); // 检查下载目录有效性    if (useDirectory)        fileName.prepend(downloadDirectory + '/'); // 如果有效则在文件名前加上目录​    if (QFile::exists(fileName)) { // 检查文件是否已存在        QString alreadyExists = useDirectory                ? tr("已存在名为%1的文件。覆盖?")                : tr("当前目录中已存在名为%1的文件。"                     "覆盖?");        QMessageBox::StandardButton response = QMessageBox::question(this,                tr("覆盖现有文件"),                alreadyExists.arg(QDir::toNativeSeparators(fileName)), // 显示确认覆盖提示                QMessageBox::Yes | QMessageBox::No, QMessageBox::No);        if (response == QMessageBox::No)            return; // 如果选择不覆盖则返回        QFile::remove(fileName); // 删除已存在的文件    }​    file = openFileForWrite(fileName); // 打开文件以写入    if (!file)        return; // 如果文件打开失败则返回​    downloadButton->setEnabled(false); // 禁用下载按钮​    // 调度请求    startRequest(newUrl);}​// 返回用于写入的文件的std::unique_ptr<QFile>std::unique_ptr<QFile> HttpWindow::openFileForWrite(const QString &fileName){    // 创建 QFile 对象并打开用于写入    std::unique_ptr<QFile> file = std::make_unique<QFile>(fileName);    if (!file->open(QIODevice::WriteOnly)) { // 校验文件是否成功打开        QMessageBox::information(this, tr("错误"),                                 tr("无法保存文件 %1: %2.")                                 .arg(QDir::toNativeSeparators(fileName),                                      file->errorString())); // 显示错误信息        return nullptr; // 返回空指针    }    return file; // 返回文件指针}​// 取消下载void HttpWindow::cancelDownload(){    statusLabel->setText(tr("下载已取消。")); // 更新状态标签    httpRequestAborted = true; // 设置请求中止标志    reply->abort(); // 中止请求    downloadButton->setEnabled(true); // 启用下载按钮}​// 请求完成void HttpWindow::httpFinished(){    qDebug() << "HttpWindow::httpFinished fileName = " << file.get()->fileName() << endl;​    QFileInfo fi; // 文件信息对象    if (file) {        fi.setFile(file->fileName()); // 设置文件信息        file->close(); // 关闭文件        file.reset(); // 重置文件指针    }​    // 检查请求是否有错误    QNetworkReply::NetworkError error = reply->error();    const QString &errorString = reply->errorString();    reply.reset(); // 重置响应指针    if (error != QNetworkReply::NoError) { // 如果发生错误        QFile::remove(fi.absoluteFilePath()); // 删除已存在的文件        if (!httpRequestAborted) { // 如果不是用户中止            // 使用 QMessageBox 显示错误信息            QMessageBox::warning(this, tr("下载错误"), tr("下载失败:\n%1.").arg(errorString));​            statusLabel->setText(tr("下载失败:\n%1.").arg(errorString)); // 更新状态标签以显示下载失败信息            downloadButton->setEnabled(true); // 启用下载按钮        }        return;    }​    statusLabel->setText(tr("已下载 %1 bytes to %2\nin\n%3")                                 .arg(fi.size())                                 .arg(fi.fileName(), QDir::toNativeSeparators(fi.absolutePath()))); // 显示下载成功信息    if (launchCheckBox->isChecked())        QDesktopServices::openUrl(QUrl::fromLocalFile(fi.absoluteFilePath())); // 如果勾选了启动文件,则打开文件    downloadButton->setEnabled(true); // 启用下载按钮}​// 下载就绪处理void HttpWindow::httpReadyRead(){    // 每当 QNetworkReply 有新数据时调用此槽。    // 读取所有新数据并写入文件中。    if (file)        file->write(reply->readAll()); // 将新数据写入到文件}​// 启用下载按钮void HttpWindow::enableDownloadButton(){    downloadButton->setEnabled(!urlLineEdit->text().isEmpty()); // 根据URL输入框内容决定按钮是否可用}​// 处理认证请求void HttpWindow::slotAuthenticationRequired(QNetworkReply *, QAuthenticator *authenticator){    qDebug() << "HttpWindow::slotAuthenticationRequired authenticator = " << authenticator << endl;​    QDialog authenticationDialog; // 创建认证对话框    Ui::Dialog ui;    ui.setupUi(&authenticationDialog); // 设置对话框UI    authenticationDialog.adjustSize(); // 调整对话框大小    ui.siteDescription->setText(tr("%1 at %2").arg(authenticator->realm(), url.host())); // 设置描述​    // 如果URL包含凭证信息,则填充UI    ui.userEdit->setText(url.userName()); // 填充用户名    ui.passwordEdit->setText(url.password()); // 填充密码​    if (authenticationDialog.exec() == QDialog::Accepted) { // 如果用户接受认证        authenticator->setUser(ui.userEdit->text()); // 设置用户名        authenticator->setPassword(ui.passwordEdit->text()); // 设置密码    }}​#if QT_CONFIG(ssl)// 处理SSL错误void HttpWindow::sslErrors(const QList<QSslError> &errors){    qDebug() << "HttpWindow::sslErrors errors.size = " << errors.size() << endl;​    QString errorString; // 错误字符串    for (const QSslError &error : errors) { // 遍历所有错误        if (!errorString.isEmpty())            errorString += '\n'; // 添加换行        errorString += error.errorString(); // 收集错误信息    }​    // 显示错误信息并询问用户忽略错误    if (QMessageBox::warning(this, tr("TLS 错误"),                             tr("发生了一个或多个TLS错误:\n%1").arg(errorString),                             QMessageBox::Ignore | QMessageBox::Abort)        == QMessageBox::Ignore) {        reply->ignoreSslErrors(); // 忽略SSL错误    }}#endif​#if QT_CONFIG(networkproxy)// 处理代理认证请求void HttpWindow::slotProxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator){    qDebug() << "HttpWindow::slotProxyAuthenticationRequired proxy.user() = " <<proxy.user() << endl;​    QDialog authenticationDialog; // 创建认证对话框    Ui::Dialog ui;    ui.setupUi(&authenticationDialog); // 设置对话框UI    authenticationDialog.adjustSize(); // 调整对话框大小    ui.siteDescription->setText(tr("位于%1的网络代理正在请求域的凭据: %2")                                        .arg(proxy.hostName(), authenticator->realm())); // 设置描述​    // 如果用户在URL中提供了凭证,则填充UI    ui.userEdit->setText(proxy.user()); // 填充代理用户名    ui.passwordEdit->setText(proxy.password()); // 填充代理密码​    if (authenticationDialog.exec() == QDialog::Accepted) { // 如果用户接受认证        authenticator->setUser(ui.userEdit->text()); // 设置用户名        authenticator->setPassword(ui.passwordEdit->text()); // 设置密码    }}#endif​
*/

11、main.cpp

代码语言:javascript
复制
#include <QApplication>#include <QDir>#include <QScreen>​// 这个项目的主要功能是下载网页文件#include "httpwindow.h"​int main(int argc, char *argv[]){    QApplication app(argc, argv);    // 居中显示处理    HttpWindow httpWin;    const QRect availableSize = httpWin.screen()->availableGeometry();    qDebug() << "main availableSize = " << availableSize << endl;    httpWin.resize(availableSize.width() / 5, availableSize.height() / 5);    httpWin.move((availableSize.width() - httpWin.width()) / 2, (availableSize.height() - httpWin.height()) / 2);    httpWin.show();​    return app.exec();}​

布局 authenticationdialog.ui

CMakeLists.txt

代码语言:javascript
复制
# 指定CMake的最低版本要求cmake_minimum_required(VERSION 3.16)​# 定义项目名称为"http",指定使用的编程语言为C++project(http LANGUAGES CXX)​# 查找所需的Qt6包,要求包含Core、Gui、Network和Widgets模块find_package(Qt6 REQUIRED COMPONENTS Core Gui Network Widgets)​# 设置项目的标准配置qt_standard_project_setup()​# 添加可执行文件目标,指定其源文件和UI文件qt_add_executable(http    authenticationdialog.ui # UI文件    httpwindow.cpp httpwindow.h # C++源文件和头文件    main.cpp # 主程序入口文件)​# 设置目标属性,指示这是一个Windows可执行文件和macOS应用程序包set_target_properties(http PROPERTIES    WIN32_EXECUTABLE TRUE # 对于Windows系统,指定为GUI应用程序(不会带有控制台)    MACOSX_BUNDLE TRUE # 对于macOS,指定为应用程序包)​# 指定链接库,设置目标与Qt6模块的链接target_link_libraries(http PRIVATE    Qt6::Core   # 链接Qt6的Core模块    Qt6::Gui    # 链接Qt6的Gui模块    Qt6::Network # 链接Qt6的Network模块    Qt6::Widgets # 链接Qt6的Widgets模块)​# 安装目标设置,定义了安装时文件的目标位置install(TARGETS http    BUNDLE  DESTINATION . # 安装应用程序包到当前目录    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # 运行时可执行文件安装到指定的运行时按件目录    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # 安装库文件到指定的库目录)​# 生成用于部署应用程序的脚本qt_generate_deploy_app_script(    TARGET http # 指定目标    OUTPUT_SCRIPT deploy_script # 输出脚本文件名    NO_UNSUPPORTED_PLATFORM_ERROR # 不报错于不支持的平台)​# 安装部署脚本install(SCRIPT ${deploy_script}) # 将生成的部署脚本安装到构建目录​

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 点击上方"蓝字"关注我们
  • ctrl+r 运行 URL可以自己替换一个试一试
  • 01、QProgressDialog
  • 02、QNetworkAccessManager
  • 03、QUrl
  • 04、memory
  • 05、QNetworkReply
  • 06、QSslError
  • 07、QAuthenticator
  • 08、http.pro
  • 09、httpwindow.h
  • 10、httpwindow.cpp
  • 11、main.cpp
  • 布局 authenticationdialog.ui
  • CMakeLists.txt
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档