文本目录
用QT开发百度文库文本下载工具
花了半天时间,终于用Visual Studion 2019 + QT + C++ 写了一个百库文库文档文本的下载工具。本工具的开发,仅出自对技术的探索和研究,并不可以对百度文库付费文档进行下载,并且只能下载文本。
缘起
以前一直使用.net、java、python写些小程序,这些开发框架使用方便,开发效率都很高。但这些框架都有一个最麻烦的事情,就是需要安装一个庞大的运行库,为软件的发布造成不便。为此花了半天时间研究了Visual Studion 2019 + QT + C++的开发技术。
Visual Studio 2019配置qt开发环境
环境的配制可以参看这一篇文章:Visual Studio 2019配置qt开发环境
需要补充说明的一点,本项目需要使用QNetWork库,这需要在创建项目时进行选择,否则头文件不能引用,编译无法通过。
在创建QT Widgets Application向导程序中,到下面这一步时,一定要在Qt Modules这里点一下,在弹出的列表中选择要使用的模块。本示例需要增加选择Network模块。
界面设计
在生成项目的“解决方案的资源管理器”中找到后缀为.ui的文件,双击就可打开QT设计师工具。
QT设计师如下图:
如果设计简单的界面,下面的经验也许能够帮助你。
精简界面
简单的界面设计,不需要菜单和工具栏以及状态栏,在右上角的对象查看器中,均可以在右键菜单中删除。
使用布局管理器简化布局设计
更改最底层的centralWidget的布局管理器为垂直布局。需要注意的事:添加一个控件之后才能更改;在设计器中右键菜单最下面可看到更改布局的菜单。这样再添加的控件就会垂直分布。
若想自动水平分布,可以再添加水平布局HorizontalLayout,再向这中添加控件。
最终控件结构如下图:
保存关闭QT设计师,在VS中编译运行程序,就可看到我们设计的程序。
QT按扭事件关联
为了让QT是响应事件,我们需要把点击事件和处理函数关联起来。在VS中,不能通过信号/槽编辑器来完成,至少我摸索了几分钟,没有发现可行的方法。常规的做法是用代码进行关联,但经过摸索,发现VS可以自动将事件和函数进行关联。自动关联时函数的名称必须起得符合规范,格式如下: on_控件名_clicked(),分别在头文件中声明,在cpp文件中实现就可以自动的关联起来。代码如下:
//头文件中添加 private slots: void on_btDownload_clicked(); //cpp中添加 void QtWenKuDownloader::on_btDownload_clicked() { }
界面控件的访问
本示例中主要要访问两种控件,它们的访问方法,可以参看他们的类说明文件就可以了。代码如下:
//从LineEdit中获取URL
QString url = ui.leUrl->text();
//将结果添加到PlainTextEdit
ui.pteHtml->appendPlainText(html);
访问网络
前面如果钩选了NetWork模块,才可以使用网络访问功能,否则无法正常添加头文件、编译时会出现无法解析的外部符号 __declspec(dllimport的错误。
想要获取网页内容,需要添加头文件
#include <QtNetwork>
网页下载函数如下:
QByteArray HttpGet(QString url) { QNetworkAccessManager manager; QEventLoop eventLoop; QObject::connect(&manager, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit())); QNetworkRequest request; request.setUrl(QUrl(url)); request.setHeader(QNetworkRequest::ContentTypeHeader, "text/plain; charset=utf-8"); request.setHeader(QNetworkRequest::UserAgentHeader, "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0"); QNetworkReply* reply = manager.get(request); eventLoop.exec(QEventLoop::ExcludeUserInputEvents); QByteArray response; if (reply->error() == QNetworkReply::NoError) { response = reply->readAll(); } else { } reply->deleteLater(); return response; }
SSL加密访问
由于百度文库的访问是通过SSL加密的,如果没有设置好,会弹出错误。解决办法如下:
下载openssl下载:http://slproweb.com/products/Win32OpenSSL.html
选择自己程序对应的版本进行安装,将openssl的bin目录下面的libcrypto-1_1-x64.dll和libssl-1_1-x64.dll库拷贝出来放到生成程序exe同级目录下即可。如果32位程序,文件名中不带x64。
正则表达式的使用
正则表达式是提取网页内容的好工具。
使用正则表达式,要包含下面的头文件:
#include <qregexp.h>
具体代码如下:
//从url中解析百度文档的ID QString ParseDocId(QString url) { //创建正则表达式解析对象 QRegExp re("view/([0-9a-f]{8,})\.html"); QString wndIndex; //用正则表达式进行查找 int pos = re.indexIn(url, 0); if (pos > 0) { return re.cap(1); } else { return ""; } }
使用QT解析Json数据
需要包含的头文件:
#include <QJsonObject>
#include <QJsonDocument>
#include <QJsonValue>
#include <QJsonArray>
示例代码如下:
QString parse_doc_content(QString content) { int lindex = content.indexOf('(') + 1; int rindex = content.lastIndexOf(')'); QString json = content.mid(lindex, rindex - lindex); QJsonParseError jsonError; QJsonDocument parseDoc = QJsonDocument::fromJson(json.toUtf8(), &jsonError); // 转化为 JSON 文档 if (parseDoc.isNull() || (jsonError.error != QJsonParseError::NoError)) { return "解析文档出错"; } QJsonArray arr = parseDoc.object().value("body").toArray(); int size = arr.size(); QJsonObject itm; QString html(""); double last_y = 0, y; for (int i = 0; i < size; i++) { itm = arr.at(i).toObject(); if (itm.value("t").toString().compare("word") == 0) { y = itm.value("p").toObject().value("y").toDouble(); if (last_y != 0 && y - last_y > 1) html.append("\n"); last_y = y; html.append(itm.value("c").toString()); } } return html; } QString getText(QString docId) { QString url = "https://wenku.baidu.com/view/" + docId + ".html"; QString html = HttpGet(url); QRegExp re("var pageData = ([^\n]*)"); int pos = re.indexIn(html, 0); if (pos > 0) { QString jstr = re.cap(1); QJsonParseError jsonError; QJsonDocument parseDoc = QJsonDocument::fromJson(jstr.mid(0, jstr.length() - 1).toUtf8(), &jsonError); // 转化为 JSON 文档 if (parseDoc.isNull() || (jsonError.error != QJsonParseError::NoError)) { return "解析文档出错"; } QJsonObject object = parseDoc.object(); if (object.contains("readerInfo2019")) { object = object.value("readerInfo2019").toObject(); } else { return "解析文档出错"; } if (object.contains("htmlUrls")) { QString html_url_content = object.value("htmlUrls").toString(); parseDoc = QJsonDocument::fromJson(html_url_content.toUtf8(), &jsonError); } else { return "解析文档出错"; } if (parseDoc.isNull() || (jsonError.error != QJsonParseError::NoError)) { return "解析文档出错"; } object = parseDoc.object(); if (object.contains("json")) { QJsonArray arr = object.value("json").toArray(); int size = arr.size(); QJsonObject itm; QString purl; QString data; QString html(""); for (int i = 0; i < size; i++) { itm = arr.at(i).toObject(); purl = itm.value("pageLoadUrl").toString(); data = HttpGet(purl); html.append(parse_doc_content(data)); } return html; } else { return "解析文档出错"; } } else { return "无法解析页面"; } }
最终结果
软件的发布
Qt5程序打包发布教程(Windows版)https://blog.csdn.net/my1324/article/details/103270782
源代码下载:
Gitee源码:https://gitee.com/zizai/qt-wen-ku-downloader
https://pan.baidu.com/s/1LsNjHMAJ43yUvNiz6D066g
提取码:4jd6
百度网盘提取二维码: