是否有任何关于 ac/cpp lib 的建议可以用来轻松(尽可能多地)解析/迭代/操作 HTML 流/文件,假设某些可能格式错误,即标签未关闭等。
4 回答
来自Libxml的HTMLparser易于使用(下面的简单教程),即使在格式错误的 HTML 上也能很好地工作。
编辑:原始博客文章不再可访问,因此我已将内容复制粘贴到此处。
在 C 中解析 (X)HTML 通常被视为一项艰巨的任务。确实,C 并不是用于开发解析器的最简单的语言。幸运的是,libxml2 的HTMLParser模块提供了帮助。因此,正如所承诺的,这里有一个小教程,解释如何使用 libxml2 的 HTMLParser 来解析 (X)HTML。
首先,您需要创建一个解析器上下文。您有很多功能可以做到这一点,具体取决于您希望如何将数据提供给解析器。我将使用
htmlCreatePushParserCtxt()
,因为它适用于内存缓冲区。htmlParserCtxtPtr parser = htmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL, 0);
然后,您可以在该解析器上下文中设置许多选项。
htmlCtxtUseOptions(parser, HTML_PARSE_NOBLANKS | HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING | HTML_PARSE_NONET);
我们现在准备解析 (X)HTML 文档。
// char * data : buffer containing part of the web page // int len : number of bytes in data // Last argument is 0 if the web page isn't complete, and 1 for the final call. htmlParseChunk(parser, data, len, 0);
一旦你推送了所有数据,你可以再次调用该函数并使用
NULL
缓冲区并1
作为最后一个参数。这将确保解析器已处理所有内容。最后,如何获取你解析的数据?这比看起来容易。您只需遍历创建的 XML 树。
void walkTree(xmlNode * a_node) { xmlNode *cur_node = NULL; xmlAttr *cur_attr = NULL; for (cur_node = a_node; cur_node; cur_node = cur_node->next) { // do something with that node information, like... printing the tag's name and attributes printf("Got tag : %s\n", cur_node->name) for (cur_attr = cur_node->properties; cur_attr; cur_attr = cur_attr->next) { printf(" ->; with attribute : %s\n", cur_attr->name); } walkTree(cur_node->children); } } walkTree(xmlDocGetRootElement(parser->myDoc));
就是这样!这还不够简单吗?从那里,你可以做任何事情,比如查找所有引用的图像(通过查看
img
标签)并获取它们,或者你能想到的任何事情。此外,您应该知道您可以随时遍历 XML 树,即使您尚未解析整个 (X)HTML 文档。
如果你必须在 C 中解析 (X)HTML,你应该使用 libxml2 的
HTMLParser
. 它将为您节省大量时间。
你可以使用 Google gumbo-parser
Gumbo 是 HTML5 解析算法的实现,它作为纯 C99 库实现,没有外部依赖项。它旨在用作其他工具和库的构建块,例如 linter、验证器、模板语言以及重构和分析工具。
#include "gumbo.h"
int main() {
GumboOutput* output = gumbo_parse("<h1>Hello, World!</h1>");
// Do stuff with output->root
gumbo_destroy_output(&kGumboDefaultOptions, output);
}
这个库gumbo-query还有一个C++绑定
一个 C++ 库,为 Google 的 Gumbo-Parser 提供类似 jQuery 的选择器。
#include <iostream>
#include <string>
#include "Document.h"
#include "Node.h"
int main(int argc, char * argv[])
{
std::string page("<h1><a>some link</a></h1>");
CDocument doc;
doc.parse(page.c_str());
CSelection c = doc.find("h1 a");
std::cout << c.nodeAt(0).text() << std::endl; // some link
return 0;
}
我只将libCurl C++用于这种类型的东西,但发现它非常好且可用。不知道它会如何处理损坏的 HTML。
尝试使用 SIP 并在其上运行 BeautifulSoup 可能会有所帮助。
有关以下链接线程的更多详细信息。开放框架 + Python