C HTML格式解析与生成之gumbo

测试
cpp 复制代码
#include <fstream>
#include <iostream>
#include <stdlib.h>
#include <string>

#include "../src/gumbo.h"

// 提取纯文本内容
static std::string cleantext(GumboNode* node) {
  if (node->type == GUMBO_NODE_TEXT) {
    return std::string(node->v.text.text);
  } else if (node->type == GUMBO_NODE_ELEMENT &&
             node->v.element.tag != GUMBO_TAG_SCRIPT &&
             node->v.element.tag != GUMBO_TAG_STYLE) {
    std::string contents = "";
    GumboVector* children = &node->v.element.children;
    for (unsigned int i = 0; i < children->length; ++i) {
      const std::string text = cleantext((GumboNode*) children->data[i]);
      if (i != 0 && !text.empty()) {
        contents.append(" ");
      }
      contents.append(text);
    }
    return contents;
  } else {
    return "";
  }
}

// 提取url链接
static void search_for_links(GumboNode* node) {
  if (node->type != GUMBO_NODE_ELEMENT) {
    return;
  }
  GumboAttribute* href;
  if (node->v.element.tag == GUMBO_TAG_A &&
      (href = gumbo_get_attribute(&node->v.element.attributes, "href"))) {
    std::cout << href->value << std::endl;
  }

  GumboVector* children = &node->v.element.children;
  for (unsigned int i = 0; i < children->length; ++i) {
    search_for_links(static_cast<GumboNode*>(children->data[i]));
  }
}

// 查找标题
#include <assert.h>
static const char* find_title(const GumboNode* root) {
  assert(root->type == GUMBO_NODE_ELEMENT);
  assert(root->v.element.children.length >= 2);

  const GumboVector* root_children = &root->v.element.children;
  GumboNode* head = NULL;
  for (int i = 0; i < root_children->length; ++i) {
    GumboNode* child = (GumboNode*) root_children->data[i];
    if (child->type == GUMBO_NODE_ELEMENT &&
        child->v.element.tag == GUMBO_TAG_HEAD) {
      head = child;
      break;
    }
  }
  assert(head != NULL);

  GumboVector* head_children = &head->v.element.children;
  for (int i = 0; i < head_children->length; ++i) {
    GumboNode* child = (GumboNode*) head_children->data[i];
    if (child->type == GUMBO_NODE_ELEMENT &&
        child->v.element.tag == GUMBO_TAG_TITLE) {
      if (child->v.element.children.length != 1) {
        return "<empty title>";
      }
      GumboNode* title_text = (GumboNode *) child->v.element.children.data[0];
      assert(title_text->type == GUMBO_NODE_TEXT ||
             title_text->type == GUMBO_NODE_WHITESPACE);
      return title_text->v.text.text;
    }
  }
  return "<no title found>";
}


static std::string find_line(
    const std::string& original_text, const GumboAttribute& attr) {
  size_t attr_index = attr.original_value.data - original_text.data();
  size_t begin = original_text.rfind("\n", attr_index) + 1;
  size_t end = original_text.find("\n", attr_index);
  if (end != std::string::npos) {
    end--;
  } else {
    end = (size_t) original_text.length() - 1;
  }
  end = std::min(end, attr_index + 40);
  begin = std::max(begin, attr_index - 40);
  return original_text.substr(begin, end - begin);
}

// 查找class元素
static void search_for_class(
    GumboNode* node, const std::string& original_text, const char* cls_name) {
  if (node->type != GUMBO_NODE_ELEMENT) {
    return;
  }
  GumboAttribute* cls_attr;
  if ((cls_attr = gumbo_get_attribute(&node->v.element.attributes, "class")) &&
      strstr(cls_attr->value, cls_name) != NULL) {
    std::cout << cls_attr->value_start.line << ":"
              << cls_attr->value_start.column << " - "
              << find_line(original_text, *cls_attr) << std::endl;
  }

  GumboVector* children = &node->v.element.children;
  for (int i = 0; i < children->length; ++i) {
    search_for_class(
        static_cast<GumboNode*>(children->data[i]), original_text, cls_name);
  }
}

int main(int argc, char** argv) {
  if (argc != 2) {
    std::cout << "Usage: clean_text <html filename>\n";
    exit(EXIT_FAILURE);
  }
  const char* filename = argv[1];

  std::ifstream in(filename, std::ios::in | std::ios::binary);
  if (!in) {
    std::cout << "File " << filename << " not found!\n";
    exit(EXIT_FAILURE);
  }

  std::string contents;
  in.seekg(0, std::ios::end);
  contents.resize(in.tellg());
  in.seekg(0, std::ios::beg);
  in.read(&contents[0], contents.size());
  in.close();

  GumboOutput* output = gumbo_parse_with_options(
      &kGumboDefaultOptions, contents.data(), contents.length());
  std::cout << cleantext(output->root) << std::endl;
  //search_for_links(output->root);
  //find_title(output->root);
  //const char* cls = "article";
  //search_for_class(output->root, contents, cls);
  gumbo_destroy_output(&kGumboDefaultOptions, output);
}
效果
参考

C HTML格式解析与生成-CSDN博客

GitHub - google/gumbo-parser: An HTML5 parsing library in pure C99


创作不易,小小的支持一下吧!

相关推荐
测试界的酸菜鱼6 分钟前
C# NUnit 框架:高效使用指南
开发语言·c#·log4j
GDAL6 分钟前
lua入门教程 :模块和包
开发语言·junit·lua
李老头探索8 分钟前
Java面试之Java中实现多线程有几种方法
java·开发语言·面试
CSXB999 分钟前
三十四、Python基础语法(文件操作-上)
开发语言·python·功能测试·测试工具
web Rookie29 分钟前
JS类型检测大全:从零基础到高级应用
开发语言·前端·javascript
很楠不爱40 分钟前
Qt——窗口
开发语言·qt
yi碗汤园40 分钟前
【一文了解】C#基础-集合
开发语言·前端·unity·c#
skaiuijing1 小时前
Sparrow系列拓展篇:对调度层进行抽象并引入IPC机制信号量
c语言·算法·操作系统·调度算法·操作系统内核
Cachel wood1 小时前
Github配置ssh key原理及操作步骤
运维·开发语言·数据库·windows·postgresql·ssh·github
დ旧言~1 小时前
【网络】应用层——HTTP协议
开发语言·网络·网络协议·http·php