目的: 為了從搜索結果中提取所有網頁,以備後續處理。 訪問百度鏈接分析 名稱 值 說明 wd 任意文字 關鍵字 rn 可以不指定,預設為10,最大為50,最小為1,可設置為任意值 一頁包含的結果條目數 pn 百度預設顯示760條,所以最後一頁為pn=750 第一條結果的索引位置 示例: https:... ...
目的:
為了從搜索結果中提取所有網頁,以備後續處理。
訪問百度鏈接分析
名稱 | 值 | 說明 |
wd | 任意文字 | 關鍵字 |
rn | 可以不指定,預設為10,最大為50,最小為1,可設置為任意值 | 一頁包含的結果條目數 |
pn | 百度預設顯示760條,所以最後一頁為pn=750 | 第一條結果的索引位置 |
示例:
https://www.baidu.com/s?wd=老虎&pn=10&rn=3
關鍵字:老虎,第10條記錄,每頁顯示3條。所以打開的是以老虎為關鍵字,第四頁的記錄
HTML源文件分析
剛下載的html源文件格式非常混亂,可使用線上html格式化工具進行格式化,以便閱讀。
根據我的需求,在HTML文件中,<script>元素與<style>元素可以直接跳過。找到搜索結果所在的位置即可。
提取搜索結果(Qt實現)
在Qt中,使用QDomDocument 或 QXmlStreamReader 來解析 HTML 文件都失敗了。經分析,其原因是:QDomDocument 或 QXmlStreamReader都是針對解析XML文件設計的。HTML與XML的區別
經過查找資料,TidyLib 庫正好可以解決問題。包包
Tidy is a console application for Mac OS X, Linux, Windows, UNIX, and more. It corrects and cleans up HTML and XML documents by fixing markup errors and upgrading legacy code to modern standards.
libtidy
is a C static and dynamic library that developers can integrate into their applications in order to bring all of Tidy’s power to your favorite tools. libtidy
is used today in desktop applications, web servers, and more.
TidyLib將HTML會修複文件可能的格式錯誤,並輸出XHTML。XHTML格式符合XML規範,可以使用QDomDocument 或 QXmlStreamReader 來解析。也可以使用TidyLib庫自帶的解析函數提取想要的元素。
#ifndef HTMLPARSE_H #define HTMLPARSE_H #include <QDomDocument> class HtmlParse { public: HtmlParse(); bool setDatas(const QByteArray& datas); QList<QDomElement> getResults(); private: private: QDomDocument doc; }; #endif // HTMLPARSE_H /*********************************************************************************/ #include "htmlparse.h" #include <QDataStream> #include <QTextStream> #include <QDebug> #include "tidy.h" #include "tidybuffio.h" #include "tidyenum.h" #include "tidyplatform.h" #include "errno.h" #include <QStandardPaths> #include <QDir> #include <QDomDocument> #include <QRegularExpression> #include <QRegularExpressionMatch> HtmlParse::HtmlParse() { } bool HtmlParse::setDatas(const QByteArray &datas) { bool result = false; TidyBuffer output = {0}; TidyBuffer errbuf = {0}; int rc = -1; Bool ok; TidyDoc tdoc = tidyCreate(); // Initialize "document" ok = tidyOptSetBool( tdoc, TidyXhtmlOut, yes ); // Convert to XHTML if ( ok ) rc = tidySetErrorBuffer( tdoc, &errbuf ); // Capture diagnostics if ( rc >= 0 ) rc = tidyParseString( tdoc, datas.data() ); // Parse the input if ( rc >= 0 ) rc = tidyCleanAndRepair( tdoc ); // Tidy it up! if ( rc >= 0 ) rc = tidyRunDiagnostics( tdoc ); // Kvetch if ( rc > 1 ) // If error, force output. rc = ( tidyOptSetBool(tdoc, TidyForceOutput, yes) ? rc : -1 ); if ( rc >= 0 ) rc = tidySaveBuffer(tdoc, &output); // Pretty Print if ( rc >= 0 ) { if (doc.setContent(QByteArray((char *)output.bp))) { result = true; } } tidyBufFree( &output ); tidyBufFree( &errbuf ); tidyRelease( tdoc ); return result; } QList<QDomElement>& findResults(const QDomNode& pnode, const QString& tagName, const QHash<QString, QString>& validators, QList<QDomElement>& results) { QDomNode n = pnode.firstChild(); while (!n.isNull()) { if (n.isElement()) { // 遞歸,當前節點的子節點 findResults(n, tagName, validators, results); QDomElement elm = n.toElement(); // 需要檢測tagName時,如果tagName不符合則跳過 if (!tagName.isEmpty() && elm.tagName() != tagName) { n = n.nextSibling(); continue; } // 取出當前節點的所有鍵值對 QHash<QString, QString> ha; auto attrs = elm.attributes(); for (int i = 0; i < attrs.count(); i++) { QDomAttr attr = attrs.item(i).toAttr(); ha.insert(attr.name(), attr.value()); } bool isValid = true; QHash<QString, QString>::const_iterator it = validators.begin(); while (it != validators.end()) { QHash<QString, QString>::const_iterator fi = ha.find(it.key()); if (fi == ha.end()) { isValid = false; break; } // 如果為空,則跳過 if (it.value().isEmpty()) { it++; continue; } QRegularExpression exp(it.value()); QRegularExpressionMatch mc = exp.match(fi.value()); if (!mc.hasMatch()) { isValid = false; break; } it++; } if (isValid) results.append(elm); } // 下一個兄弟節點 n = n.nextSibling(); } return results; } QList<QDomElement > HtmlParse::getResults() { QList<QDomElement> elements; QList<QDomElement> hrefElements; QHash<QString, QString> validators; validators.insert("class", "result"); validators.insert("id", "\\d+"); validators.insert("srcid", "\\d+"); findResults(doc, "div", validators, elements); qDebug() << elements.count(); for (auto var : elements) { qDebug() << var.attribute("id"); validators.clear(); validators.insert("href", ""); findResults(var, "a", validators, hrefElements); for (auto href : hrefElements) { qDebug() << href.text() << href.attribute("href"); } } return hrefElements; }