百度搜索結果HTML分析

目的:

爲了從搜索結果中提取全部網頁,以備後續處理。html

 

訪問百度連接分析

名稱 說明
wd 任意文字 關鍵字
rn 能夠不指定,默認爲10,最大爲50,最小爲1,可設置爲任意值 一頁包含的結果條目數
pn 百度默認顯示760條,因此最後一頁爲pn=750 第一條結果的索引位置

示例:

https://www.baidu.com/s?wd=老虎&pn=10&rn=3node

關鍵字:老虎,第10條記錄,每頁顯示3條。因此打開的是以老虎爲關鍵字,第四頁的記錄web

 

HTML源文件分析

剛下載的html源文件格式很是混亂,可以使用在線html格式化工具進行格式化,以便閱讀。app

根據個人需求,在HTML文件中,<script>元素與<style>元素能夠直接跳過。找到搜索結果所在的位置便可。ide

image

 

image

 

 

提取搜索結果(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. spa

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庫自帶的解析函數提取想要的元素。code

 

#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;
}
相關文章
相關標籤/搜索