get-driver-info-cpp

介绍

基于C++语言通过网络爬虫的方式获取小米笔记本的驱动信息,该项目已上传至码云Github

软件架构

基于 Qt 5.12.10 以及 C++ 17 进行开发,其中借助于 dataframe-cpp 读取和存储驱动信息到文件。

代码讲解

首先是下载器类的实现,代码如下:

#ifndef DOWNLOADER_HPP
#define DOWNLOADER_HPP

#include <iostream>
#include <QtNetwork>

class Downloader : public QObject{
    Q_OBJECT

    QNetworkAccessManager *manager;
    QNetworkReply *reply;
    QUrl url;
    QFile *file;
    QEventLoop * loop;
public:
    Downloader(QString urlstr, QEventLoop * loop_ = nullptr){
        url = urlstr;
        loop = loop_;
        manager = new QNetworkAccessManager(this);
        reply = manager->get(QNetworkRequest(url));

        QFileInfo info(url.path());
        QString fileName(info.fileName());

        if (fileName.isEmpty()) fileName = "index.html";

        file = new QFile(fileName);

        if(!file->open(QIODevice::WriteOnly))
        {
            qDebug() << "file open error";
            delete file;
            file = nullptr;
            return;
        }else qDebug() << fileName<< " is downloading ...";

        connect(reply,SIGNAL(finished()),this,SLOT(finished()));
        connect(reply,SIGNAL(readyRead()),this,SLOT(readyRead()));
    }

private slots:
    void readyRead() {
        if (file) file->write(reply->readAll());  //如果文件存在,则写入文件
    }

    void finished() {
        file->flush();
        file->close();
        reply->deleteLater();
        reply = nullptr;
        delete file;
        file = nullptr;
        if(loop != nullptr)
            loop->quit();
    }
};

#endif // DOWNLOADER_HPP

其中下面两个信号和槽的连接实现了下载中文件写入和下载完临时变量处理

connect(reply,SIGNAL(finished()),this,SLOT(finished()));
connect(reply,SIGNAL(readyRead()),this,SLOT(readyRead()));

同时使用下面两句话实现根据URL自动设置文件名

QFileInfo info(url.path());
QString fileName(info.fileName());

下面讲解爬虫的核心代码,这里借助于Qt中的QRegExp实现HTML源代码的解析,注意本文所解析的是使用HTTP协议的网址,并且非动态加载。为了先验证源码解析的可行性,本文先从Python代码入手,Python的源码如下:

import re
import os
import sys
import time
import signal
import chardet
import requests
import urllib.request

homepage = "https://www.mi.com/service/bijiben/drivers/A29"

def print_drivers_info(driver_item_dict):
	for type_name in driver_item_dict:
		print("类别:",type_name)
		for item_name in driver_item_dict[type_name]:
			print(item_name,end=" ")
			print("\t大小 :",driver_item_dict[type_name][item_name]["size"] ,end=" ")
			print("\t下载链接 :",driver_item_dict[type_name][item_name]["download_url"])
		print()

def get_driver_info(homepage):
	page= urllib.request.urlopen(homepage) #打开网页
	htmlCode = page.read() #获取网页源代码
	htmlCode = htmlCode.decode(chardet.detect(htmlCode)["encoding"]) #网页源代码解码
	reg = r'\"main_body\":{\"section\":\[{\"body\":{\"section\":\[(.*?)\],\"sub_title\":\"适用于Windows 10操作系统\",\"title\":\"请选择驱动类型\"},\"view_type\":\"driver_info\"}\]}' 
	reg = re.compile(reg)
	driver_info = reg.findall(htmlCode)

	reg = r'{\"items\":\[(.*?)\],\"title\":\"(.*?)\"}' 
	reg = re.compile(reg)
	driver_items = reg.findall(driver_info[0])

	driver_item_dict = dict()

	for driver_item in driver_items:
		type_name = driver_item[1].replace(" ","")
		driver_item_dict[type_name] = {}
		reg = r'{\"description\":\"(.*?)\",\"download_url\":\"(.*?)\",\"id\":(.*?),\"img_url\":\"(.*?)\",\"title\":\"(.*?)\"}' 
		reg = re.compile(reg)
		driver_subitems = reg.findall(driver_item[0])
		
		for driver_subitem in driver_subitems:
			item_name = driver_subitem[4].replace(" ","")
			driver_item_dict[type_name][item_name] = {}
			driver_item_dict[type_name][item_name]["size"] = driver_subitem[0].replace(" ","")
			driver_item_dict[type_name][item_name]["download_url"] = driver_subitem[1].replace(" ","")
			driver_item_dict[type_name][item_name]["id"] = driver_subitem[2].replace(" ","")
			driver_item_dict[type_name][item_name]["img_url"] = driver_subitem[3].replace(" ","")
	print_drivers_info(driver_item_dict)

get_driver_info(homepage)

其中下面三句话是根据网站样式匹配的正则,(.*?)可以匹配所有东西,加括号代表该部分为我们需要的字符串。读者也可以根据自己的需求,设计匹配正则。

reg = r'\"main_body\":{\"section\":\[{\"body\":{\"section\":\[(.*?)\],\"sub_title\":\"适用于Windows 10操作系统\",\"title\":\"请选择驱动类型\"},\"view_type\":\"driver_info\"}\]}' 
reg = r'{\"items\":\[(.*?)\],\"title\":\"(.*?)\"}' 
reg = r'{\"description\":\"(.*?)\",\"download_url\":\"(.*?)\",\"id\":(.*?),\"img_url\":\"(.*?)\",\"title\":\"(.*?)\"}'

与之相对应的部分网页源码如下:

PageData: {"breadcrumbs":[{"action":{"path":"service","type":"url"},"id":9,"m_jump_url":"","name":"帮助中心","type":"page"},{"action":{"path":"service/bijiben","type":"url"},"id":154,"m_jump_url":"","name":"小米笔记本及周边产品","type":"url"},{"action":{"path":"service/bijiben/drivers","type":"url"},"id":155,"m_jump_url":"","name":"驱动下载","type":"page"},{"action":{"path":"service/bijiben/drivers/A29","type":"url"},"id":462,"m_jump_url":"","name":"RedmiBook Pro 15","type":"page"}],"left_tree":{"all_menu":[{"action":{"path":"service/bijiben/drivers","type":"url"},"id":155,"m_jump_url":"","name":"驱动下载","type":"page"},{"action":{"path":"service/bijiben/welcome","type":"url"},"id":160,"m_jump_url":"","name":"欢迎","type":"page"},{"action":{"path":"service/bijiben/support","type":"url"},"id":161,"m_jump_url":"","name":"常见问题","type":"page"},{"action":{"path":"service/bijiben/firstuse","type":"url"},"id":162,"m_jump_url":"","name":"首次使用","type":"page"},{"action":{"path":"service/bijiben/hardware-expansion","type":"url"},"id":163,"m_jump_url":"","name":"添加硬件与分区","type":"page"},{"action":{"path":"service/bijiben/Reset","type":"url"},"id":164,"m_jump_url":"","name":"重置系统","type":"page"},{"action":{"path":"service/bijiben/install-the-program","type":"url"},"id":165,"m_jump_url":"","name":"安装程序","type":"page"},{"action":{"path":"service/bijiben/key-function","type":"url"},"id":166,"m_jump_url":"","name":"按键功能","type":"page"},{"action":{"path":"service/bijiben/Office","type":"url"},"id":255,"m_jump_url":"","name":"Office激活与使用","type":"page"}],"fixed_menu":[{"action":{"path":"service/contact","type":"url"},"name":"联系客服"}],"parent_menu":{"action":{"path":"service/bijiben/drivers","type":"url"},"id":155,"m_jump_url":"","name":"驱动下载","type":"page"}},"m_jump_url":"","main_body":{"section":[{"body":{"section":[{"items":[{"description":"11GB","download_url":"https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/Image/A29_Image_Recovery_20H2_V3.5.zip","id":890,"img_url":"https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/17e339b9d687bceef9ef5cd847d4a5b0.png","title":"系统恢复"},{"description":"182MB","download_url":"https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A18A29/20210304/%E5%BA%94%E7%94%A8%E8%BD%AF%E4%BB%B6.zip","id":853,"img_url":"https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/14039fc790628d99db4bfb68f9141472.png","title":"应用软件           "},{"description":"78MB","download_url":"https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A18A29/20210423/%E6%9C%8D%E5%8A%A1%E4%B8%AD%E5%BF%83.zip","id":872,"img_url":"https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/783e585a1a790398091129f2aa0b0a8d.png","title":"服务中心           "},{"description":"178MB","download_url":"https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A18A29/20210304/MIUI%2B.zip","id":855,"img_url":"https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/0d3af6a987aa5c5e44065f2bf8a9c73e.png","title":"MIUI+"}],"title":"系统恢复及应用"},{"items":[{"description":"54MB","download_url":"https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/WLAN_22.10.0.7.zip","id":874,"img_url":"https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/3690a41b3c1f1b66c38e71d3c78be97e.png","title":"无线网卡           "},{"description":"515MB","download_url":"https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/IntelVGA_27.20.100.8935.zip","id":875,"img_url":"https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/4d7f4c6aa5287edf76dc82c413180e2d.png","title":"集成显卡            "},{"description":"842MB","download_url":"https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/Nvidia_27.21.14.5763.zip","id":876,"img_url":"https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/4d7f4c6aa5287edf76dc82c413180e2d.png","title":"独立显卡            "},{"description":"611MB","download_url":"https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/Audio_9075.zip","id":877,"img_url":"https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/a413a07c62e684ce0ba94e4906815650.png","title":"声卡                "},{"description":"54MB","download_url":"https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/BT_22.10.0.2.zip","id":878,"img_url":"https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/eb67c59b26b96c3356f15a213dda49d7.png","title":"蓝牙                "},{"description":"10MB","download_url":"https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210310/FPR_E_10301_G_230_F_11.26.1.41.zip","id":879,"img_url":"https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/d7857b2cb2e747f45f1ea5831cb67d00.png","title":"指纹识别"},{"description":"18MB","download_url":"https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/TBT_1.41.1054.zip","id":880,"img_url":"https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/f76b2f708de562c0430d147ae37ea178.png","title":"英特尔TBT"}],"title":"固件外设"},{"items":[{"description":"22KB","download_url":"https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/Chipset_10.1.24.5.zip","id":881,"img_url":"https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/7542212384c31a8e89e1e2c409281328.png","title":"芯片组驱动          "},{"description":"18MB","download_url":"https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/ME_2040.100.0.1029.zip","id":882,"img_url":"https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/792018351236eaefab01bfc0f44582b0.png","title":"芯片组管理引擎      "},{"description":"2MB","download_url":"https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/SerialIO_30.100.2031.2.zip","id":883,"img_url":"https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/a5edc351404a841677ccca4d5d426663.png","title":"芯片组串行输入输出  "},{"description":"7MB","download_url":"https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/DPTF_8.7.10401.16510.zip","id":884,"img_url":"https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/c684bc0fd58c52cbe0569033ef55600a.png","title":"散热               "},{"description":"1KB","download_url":"https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/power%20management.zip","id":885,"img_url":"https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/07a8d2c1472ee16af16a579bb64208be.png","title":"电源管理优化        "},{"description":"52KB","download_url":"https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/GNA_Driver_2.0.0.1047.zip","id":886,"img_url":"https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/a89244a30b27abb280222f845aeac416.png","title":"英特尔GNA"}],"title":"系统性能"},{"items":[{"description":"10MB","download_url":"https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A18A29/20210423/OSD.zip","id":887,"img_url":"https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/4d7f4c6aa5287edf76dc82c413180e2d.png","title":"OSD快捷键功能显示    "}],"title":"快捷键"},{"items":[{"description":"9MB","download_url":"https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/BIOS/A29/20210413/RMATG5B0P0909.zip","id":888,"img_url":"https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/7cf33db46a6894d211646e70b1fef4bb.png","title":"BIOS"}],"title":"BIOS"}],"sub_title":"适用于Windows 10操作系统","title":"请选择驱动类型"},"view_type":"driver_info"}]},"page_template":"4","seo":{"description":"","keywords":"","title":""}},

该代码运行后的打印信息如下:

类别: 系统恢复及应用
系统恢复        大小 : 11GB     下载链接 : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/Image/A29_Image_Recovery_20H2_V3.5.zip
应用软件        大小 : 182MB    下载链接 : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A18A29/20210304/%E5%BA%94%E7%94%A8%E8%BD%AF%E4%BB%B6.zip
服务中心        大小 : 78MB     下载链接 : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A18A29/20210423/%E6%9C%8D%E5%8A%A1%E4%B8%AD%E5%BF%83.zip
MIUI+   大小 : 178MB    下载链接 : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A18A29/20210304/MIUI%2B.zip

类别: 固件外设
无线网卡        大小 : 54MB     下载链接 : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/WLAN_22.10.0.7.zip
集成显卡        大小 : 515MB    下载链接 : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/IntelVGA_27.20.100.8935.zip
独立显卡        大小 : 842MB    下载链接 : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/Nvidia_27.21.14.5763.zip
声卡    大小 : 611MB    下载链接 : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/Audio_9075.zip
蓝牙    大小 : 54MB     下载链接 : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/BT_22.10.0.2.zip
指纹识别        大小 : 10MB     下载链接 : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210310/FPR_E_10301_G_230_F_11.26.1.41.zip
英特尔TBT       大小 : 18MB     下载链接 : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/TBT_1.41.1054.zip

类别: 系统性能
芯片组驱动      大小 : 22KB     下载链接 : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/Chipset_10.1.24.5.zip
芯片组管理引擎  大小 : 18MB     下载链接 : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/ME_2040.100.0.1029.zip
芯片组串行输入输出      大小 : 2MB      下载链接 : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/SerialIO_30.100.2031.2.zip
散热    大小 : 7MB      下载链接 : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/DPTF_8.7.10401.16510.zip
电源管理优化    大小 : 1KB      下载链接 : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/power%20management.zip
英特尔GNA       大小 : 52KB     下载链接 : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/GNA_Driver_2.0.0.1047.zip

类别: 快捷键
OSD快捷键功能显示       大小 : 10MB     下载链接 : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A18A29/20210423/OSD.zip

类别: BIOS
BIOS    大小 : 9MB      下载链接 : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/BIOS/A29/20210413/RMATG5B0P0909.zip

确定爬虫实现的可行性后,进行C++代码的设计,其实现如下:

#include <QCoreApplication>
#include <QObject>
#include <QtCore>
#include <downloader.hpp>
#include <dataframe.hpp>
#include <unordered_map>
#include <iostream>
#include <cstdio>
#include <QDateTime>

QString getSpaceStr(int num, char delimeter = ' ') {
    QString temp;
    while (num--) {
        temp.append(delimeter);
    }
    return temp;
}

int main(int argc, char **argv) {
    QCoreApplication app(argc, argv);
    QFile file("URLSTR");
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() << "Please enter the correct URL of your mi computer in the file!";
    } else {
        QByteArray line = file.readLine();
        QString URLSTR = QString::fromLocal8Bit(line);
        if(line.size() <= 0) {
            qDebug() << "Please enter the correct URL of your mi computer in the file!";
        } else {
            QUrl url(URLSTR);
            QNetworkAccessManager manager;
            QEventLoop loop;
            QNetworkReply *reply;

            qDebug() << "Reading html code from " << URLSTR;
            reply = manager.get(QNetworkRequest(url));
            QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
            loop.exec();

            QString codeContent = reply->readAll();

            QString str_1 = "main_body\":\\\{\"section\":\\\[\\\{\"body\":\\\{\"section\":\\\[(.*)\\\].*view_type\":\"driver_info";

            QRegExp rx_1(str_1);

            std::unordered_map<int, std::vector<std::vector<user_variant>>> dict;
            std::vector<flame::dataframe < user_variant> * > type_dataframe;

            int max_length_name = 0;
            int pos_1 = 0;
            pos_1 = rx_1.indexIn(codeContent, pos_1);
            std::vector<bool> no_file = {false, false, false, false, false};
            if (pos_1 >= 0) {
                QString str_2 = "\\\{\"items\":\\\[(.*)\\\],\"title\":\"(.*)\"\\\}";
                QRegExp rx_2(str_2);
                rx_2.setMinimal(true);
                int pos_2 = 0;
                int type_num = 0;
                while (pos_2 >= 0) {
                    pos_2 = rx_2.indexIn(rx_1.cap(1), pos_2);
                    if (pos_2 >= 0) {
                        ++pos_2;
                        auto data_save = new flame::dataframe(rx_2.cap(2).toLocal8Bit().toStdString());
                        if (data_save->column_num() == 0) {
                            data_save->column_paste({"name", "size", "download URL"});
                            if (no_file.size() > type_num)
                                no_file[type_num] = true;
                            else no_file.push_back(true);
                        }
                        type_dataframe.push_back(data_save);
                        QString str_3 = "\\\{\"description\":\"(.*)\",\"download_url\":\"(.*)\",\"id\":(.*),\"img_url\":\"(.*)\",\"title\":\"(.*)\"\\\}";
                        QRegExp rx_3(str_3);
                        rx_3.setMinimal(true);
                        int pos_3 = 0;
                        int row_num = 0;
                        while (pos_3 >= 0) {
                            pos_3 = rx_3.indexIn(rx_2.cap(1), pos_3);
                            if (pos_3 >= 0) {
                                ++pos_3;

                                if (int(data_save->row_num()) - 1 < row_num) {
                                    data_save->append({rx_3.cap(5).replace(" ", "").toStdString(),
                                                       rx_3.cap(1).replace(" ", "").toStdString(),
                                                       rx_3.cap(2).replace(" ", "").toStdString()});
                                    if (no_file.size() > type_num)
                                        no_file[type_num] = true;
                                    else no_file.push_back(true);
                                } else if (std::get<std::string>((*data_save)[row_num][2]) !=
                                           rx_3.cap(2).replace(" ", "").toStdString() ||
                                           std::get<std::string>((*data_save)[row_num][1]) !=
                                           rx_3.cap(1).replace(" ", "").toStdString() ||
                                           std::get<std::string>((*data_save)[row_num][0]) !=
                                           rx_3.cap(5).replace(" ", "").toStdString()) {
                                    if (dict.find(type_num) != dict.end()) {
                                        dict[type_num].emplace_back(std::vector<user_variant>{row_num,
                                                                                              rx_3.cap(5).replace(" ",
                                                                                                                  "").toStdString(),
                                                                                              rx_3.cap(1).replace(" ",
                                                                                                                  "").toStdString(),
                                                                                              rx_3.cap(2).replace(" ",
                                                                                                                  "").toStdString()});
                                    } else {
                                        dict.insert(std::pair<int, std::vector<std::vector<user_variant>>>(type_num, {
                                                {row_num, rx_3.cap(5).replace(" ", "").toStdString(),
                                                        rx_3.cap(1).replace(" ", "").toStdString(),
                                                        rx_3.cap(2).replace(" ", "").toStdString()}}));
                                    }
                                }

                                if (max_length_name < rx_3.cap(5).replace(" ", "").toLocal8Bit().size())
                                    max_length_name = rx_3.cap(5).replace(" ", "").toLocal8Bit().size();

                                row_num++;
                            }
                        }
                    }
                    type_num++;
                }

                std::cout << "Infomation of last upgrade packages of drivers : " << std::endl;
                for (auto items = type_dataframe.begin(); items != type_dataframe.end(); items++) {
                    std::cout << (*items)->name() << std::endl;
                    for (int index = 0; index < (*items)->row_num(); index++) {
                        QString DownloadURL = QString::fromStdString(std::get<std::string>((*(*items))[index][2]));
                        qDebug().noquote().nospace() << " |—"
                                                     << QString::fromStdString(std::get<std::string>((*(*items))[index][0]))
                                                     << getSpaceStr(max_length_name - QString::fromStdString(
                                                             std::get<std::string>(
                                                                     (*(*items))[index][0])).toLocal8Bit().size())
                                                     << "\t Size : "
                                                     << QString::fromStdString(std::get<std::string>((*(*items))[index][1]))
                                                     << "\t Time : "
                                                     << (QDateTime::fromString(*(DownloadURL.split('/').end() - 2),
                                                                               "yyyyMMdd").isValid() ? *(
                                                             DownloadURL.split('/').end() - 2) : "xxxxxxxx")
                                                     << "\t Download URL : " << DownloadURL;
                    }
                    std::cout << std::endl;
                }
                if (!dict.empty())
                    std::cout << "Available upgrade installation packages of current drivers : " << std::endl;
                for (auto items = dict.begin(); items != dict.end(); items++) {
                    std::cout << type_dataframe[items->first]->name() << std::endl;
                    for (auto item = items->second.begin(); item != items->second.end(); item++) {
                        QString DownloadURL = QString::fromStdString(std::get<std::string>((*item)[3]));
                        qDebug().noquote().nospace() << " |—"
                                                     << QString::fromStdString(std::get<std::string>((*item)[1]))
                                                     << getSpaceStr(max_length_name - QString::fromStdString(
                                                             std::get<std::string>((*item)[1])).toLocal8Bit().size())
                                                     << "\t Size : "
                                                     << QString::fromStdString(std::get<std::string>((*item)[2]))
                                                     << "\t Time : "
                                                     << (QDateTime::fromString(*(DownloadURL.split('/').end() - 2),
                                                                               "yyyyMMdd").isValid() ? *(
                                                             DownloadURL.split('/').end() - 2) : "xxxxxxxx")
                                                     << "\t Download URL : " << DownloadURL;
                    }
                    std::cout << std::endl;
                }

                if (!dict.empty()) {
                    std::string answer;
                    std::cout << "Update drivers or not [Yes/No] : ";
                    std::cin >> answer;
                    if (answer == "Yes") {
                        std::cout << "Download program installation package automatically or not [Yes/No] : ";
                        answer.clear();
                        std::cin >> answer;

                        QFile *file = nullptr;
                        bool file_ok = true;
                        if (answer == "No") {
                            file = new QFile("ChangeLog.TXT");
                            if (!file->open(QIODevice::WriteOnly | QIODevice::Text)) {
                                std::cout << "Write into info file failed !";
                                file_ok = false;
                            }
                        }

                        for (auto items = dict.begin(); items != dict.end(); items++) {
                            for (auto item = items->second.begin(); item != items->second.end(); item++) {
                                (*type_dataframe[items->first])[std::get<int>((*item)[0])] = {(*item)[1], (*item)[2],
                                                                                              (*item)[3]};
                                if (answer == "Yes") {
                                    Downloader downloader(QString::fromStdString(std::get<std::string>((*item)[3])), &loop);
                                    loop.exec();
                                } else if (file_ok) {
                                    QTextStream out(file);
                                    QString DownloadURL = QString::fromStdString(std::get<std::string>((*item)[3]));
                                    out << QString::fromStdString(std::get<std::string>((*item)[1]))
                                        << getSpaceStr(max_length_name - QString::fromStdString(
                                                std::get<std::string>((*item)[1])).toLocal8Bit().size())
                                        << "\t Size : " << QString::fromStdString(std::get<std::string>((*item)[2]))
                                        << "\t Time : "
                                        << (QDateTime::fromString(*(DownloadURL.split('/').end() - 2), "yyyyMMdd").isValid()
                                            ? *(DownloadURL.split('/').end() - 2) : "xxxxxxxx")
                                        << "\t Download URL : " << DownloadURL << '\n';
                                }
                                type_dataframe[items->first]->to_csv();
                            }
                        }

                        if (answer == "No") {
                            file->close();
                            delete file;
                            if (file_ok) {
                                qDebug() << "Change information has been written to ChangeLog.TXT the file, please update the drivers manually !";
                            }
                        }
                    }
                } else qDebug() << "No upgrade package of driver !";

                type_num = 0;
                for (auto no_file_flag = no_file.begin(); no_file_flag != no_file.end(); no_file_flag++, type_num++) {
                    if (*no_file_flag) {
                        type_dataframe[type_num]->to_csv();
                    }
                }

                for (auto dataframe_item = type_dataframe.begin(); dataframe_item != type_dataframe.end(); dataframe_item++)
                    delete *dataframe_item;
            } else qDebug() << "Information of drivers  is parsed failed, please check your URL !";
        }
    }
    system("pause");
    return 0;
}

其中下面三句是根据网站样式匹配的正则,可以看出于Python下有些许差别这是根据编码不同,接口使用方法不同导致的,但其使用方式于Python下的实现类似。

QString str_1 = "main_body\":\\\{\"section\":\\\[\\\{\"body\":\\\{\"section\":\\\[(.*)\\\].*view_type\":\"driver_info";
QString str_2 = "\\\{\"items\":\\\[(.*)\\\],\"title\":\"(.*)\"\\\}";
QString str_3 = "\\\{\"description\":\"(.*)\",\"download_url\":\"(.*)\",\"id\":(.*),\"img_url\":\"(.*)\",\"title\":\"(.*)\"\\\}";

最终该项目实现了从URLSTR文件读取网址后获取当前最新驱动信息、上一次更新后的驱动信息以及需要更新的驱动信息,并将其打印,以及选择是否更新和自动下载,如果选择更新,将会通过dataframe接口保存最新驱动到本地文件,如果选择自动下载,将会将安装包下载至本地,如果选择手动下载则会保存信息到ChangeLog.TXT文件中。最终的打印信息如下:

Reading html code from  "https://www.mi.com/service/bijiben/drivers/A29"
Infomation of last upgrade packages of drivers :
系统恢复及应用
 |—系统恢复             Size : 11GB     Time : xxxxxxxx         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/Image/A29_Image_Recovery_20H2_V3.5.zip
 |—应用软件             Size : 182MB    Time : 20210304         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A18A29/20210304/%E5%BA%94%E7%94%A8%E8%BD%AF%E4%BB%B6.zip
 |—服务中心             Size : 78MB     Time : 20210423         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A18A29/20210423/%E6%9C%8D%E5%8A%A1%E4%B8%AD%E5%BF%83.zip
 |—MIUI+                Size : 178MB    Time : 20210304         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A18A29/20210304/MIUI%2B.zip

固件外设
 |—无线网卡             Size : 54MB     Time : 20210301         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/WLAN_22.10.0.7.zip
 |—集成显卡             Size : 515MB    Time : 20210301         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/IntelVGA_27.20.100.8935.zip
 |—独立显卡             Size : 842MB    Time : 20210301         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/Nvidia_27.21.14.5763.zip
 |—声卡                 Size : 611MB    Time : 20210301         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/Audio_9075.zip
 |—蓝牙                 Size : 54MB     Time : 20210301         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/BT_22.10.0.2.zip
 |—指纹识别             Size : 10MB     Time : 20210310         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210310/FPR_E_10301_G_230_F_11.26.1.41.zip
 |—英特尔TBT            Size : 18MB     Time : 20210301         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/TBT_1.41.1054.zip

系统性能
 |—芯片组驱动           Size : 22KB     Time : xxxxxxxx         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20211/Chipset_10.1.24.5.zip
 |—芯片组管理引擎       Size : 18MB     Time : 20210301         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/ME_2040.100.0.1029.zip
 |—芯片组串行输入输出   Size : 2MB      Time : 20210301         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/SerialIO_30.100.2031.2.zip
 |—散热                 Size : 7MB      Time : 20210301         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/DPTF_8.7.10401.16510.zip
 |—电源管理优化         Size : 1KB      Time : 20210301         Download URL : https://cdn.cnbj1.fds.api.mi-imgm/mibook-drivers/A29/20210301/power%20management.zip
 |—英特尔GNA            Size : 52KB     Time : 20210301         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/GNA_Driver_2.0.0.1047.zip

快捷键
 |—OSD快捷键功能显示    Size : 10MB     Time : 20210423         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A18A29/20210423/OSD.zip

BIOS
 |—BIOS                 Size : 9MB      Time : 20210413         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/BIOS/A29/20210413/RMATG5B0P0909.zip

Available upgrade installation packages of current drivers :
系统性能
 |—芯片组驱动           Size : 22KB     Time : 20210301         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/Chipset_10.1.24.5.zip
 |—电源管理优化         Size : 1KB      Time : 20210301         Download URL : https://cdn.cnbj1.fds.api.mi-img.com/mibook-drivers/A29/20210301/power%20management.zip

Update drivers or not [Yes/No] : Yes
Download program installation package automatically or not [Yes/No] : No
Change information has been written to ChangeLog.TXT the file, please update the drivers manually !