如何使用QT解析HTML文件?

4
目标是获取一个类似于QDomDocument的对象,其内容为HTML(而非XML)文档。问题在于,一些标签,尤其是script标签会触发错误:
<!DOCTYPE html>
<html>
<head>
    <script type="text/javascript">
        var a = [1,2,3];
        var b = (2<a.length);
    </script>
</head>
<body/>
</html>

格式错误:元素类型“a.length”后面必须跟随属性规范、“>”或“/>”。

我知道HTML与XML不同,但是Qt应该有解决此问题的方法:

  • 将解析器设置为接受HTML
  • 另一个用于HTML的类
  • 一种将某些标签名称设置为CDATA的方法。

我的当前尝试只能实现普通的XML解析:

QString mainHtml;

{
    QFile file("main.html");
    if (!file.open(QIODevice::ReadOnly)) qDebug() << "Error reading file main.html";
    QTextStream stream(&file);
    mainHtml = stream.readAll();
    file.close();
}

QQDomDocument doc;
QString errStr;
int errLine=0, errCol=0;
doc.setContent( mainHtml, false, &errStr, &errLine, &errCol);
if (!errStr.isEmpty())
{
    qDebug() << errStr << "L:" << errLine << ":" << errCol;
}

std::function<void(const QDomElement&, int)> printTags=
[&printTags](const QDomElement& elem, int tab)
{
    QString space(3*tab, ' ');
    QDomNode n = elem.firstChild();
    for( ;!n.isNull(); n=n.nextSibling()) 
    {
        QDomElement e = n.toElement();
        if(e.isNull()) continue;
        
        qDebug() << space + e.tagName(); 
        printTags( e, tab+1);
    }
};
printTags(doc.documentElement(), 0);

注意:我希望避免为此包含完整的webkit。

1
您可以使用各种第三方库将HTML转换为XHTML,然后使用Qt的XML解析器进行解析。但请注意手册中有关不要在现代Qt代码中使用QDomDocument的部分。 - MrEricSir
特别是现代Qt代码中不要使用QDomDocument的部分。呃,好细节! - Adrian Maire
2
这里有一个第三方库可以帮助将 HTML 转换为 XML:tidy-html5。我自己也用它来完成同样的目标,虽然有一些小问题,但还是能用的;这里是一个在 Qt 项目中使用它的例子,以防万一。 - Dmitry
我明白了,谢谢你。 - Adrian Maire
1个回答

3
我建议使用 htmlcxx。它是在LPGL下许可的。它可以在Linux和Windows上工作。如果您使用Windows,请使用 msys 进行编译。
要编译它,只需提取文件并运行。
./configure --prefix=/usr/local/htmlcxx
make
make install

在您的 .pro 文件中添加包含和库目录。
INCLUDEPATH += /usr/local/htmlcxx/include
LIBS += -L/usr/local/htmlcxx/lib -lhtmlcxx

使用示例

#include <iostream>
#include "htmlcxx/html/ParserDom.h"
#include <stdlib.h>

int main (int argc, char *argv[])
{
  using namespace std;
  using namespace htmlcxx;

  //Parse some html code
  string html = "<html><body>hey<A href=\"www.bbxyard.com\">myhome</A></body></html>";
  HTML::ParserDom parser;
  tree<HTML::Node> dom = parser.parseTree(html);
  //Print whole DOM tree
  cout << dom << endl;

  //Dump all links in the tree
  tree<HTML::Node>::iterator it = dom.begin();
  tree<HTML::Node>::iterator end = dom.end();
  for (; it != end; ++it)
  {
     if (strcasecmp(it->tagName().c_str(), "A") == 0)
     {
       it->parseAttributes();
       cout << it->attribute("href").second << endl;
     }
  }

  //Dump all text of the document
  it = dom.begin();
  end = dom.end();
  for (; it != end; ++it)
  {
    if ((!it->isTag()) && (!it->isComment()))
    {
      cout << it->text() << " ";
    }
  }
  cout << endl;
  return 0;
}

示例致谢:https://github.com/bbxyard/sdk/blob/master/examples/htmlcxx/htmlcxx-demo.cpp

HTML不能使用XML解析器。您可以使用htmlcxx或将HTML转换为有效的XML,然后可以自由使用QDomDocument、Qt XML解析器等。

QWebEngine也具有解析功能,但会给应用程序带来很大的开销。


我认为你的“在树中转储所有链接”可以更简单: for (auto it: dom) { if (it.tagName()=="A") { it.parseAttributes(); cout << it.attribute("href").second << endl; } } - Adrian Maire
1
@Adrian Maire,感谢您提供的信息。我没有写示例代码。我已经在代码示例下方添加了GitHub链接以表彰原作者。无论如何,我可以确认htmlcxx在我的Qt项目中运行良好。我爬取大型网站并解析一些属性。 - user3606329

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接