C HTML格式解析与生成之gumbo

news2024/11/13 9:16:30
测试

#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


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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2147913.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【TabBar嵌套Navigation案例-关于页面 Objective-C语言】

一、关于页面 1.首先,看一下我们的示例程序 点击关于以后,它实际上,跳到的也是SettingController,然后呢,传一个plist,但是,这个Controller里边,又多了一个header,所以,这个里边,我们也是用继承的方式去写,因为其他的页面没有这个header,不是所有的Setting都有he…

数据结构--结构体数组和结构体指针

1.定义结构体数组存储5个学生的信息&#xff1a;姓名&#xff0c;年龄&#xff0c;性别 定义函数实现输入&#xff0c;要求形参使用结构体指针接收 函数实现5个学生年龄排序(注意对年龄排序时&#xff0c;交换的是所有信息) 定义函数实现输出&#xff0c;要求形参使用结构体…

Innovus跑到中途想要更换library怎么办?

有的小伙伴在跑innovus时&#xff0c;可能会碰到library更新等问题。但此时&#xff0c;place已经跑完了&#xff0c;又不想重新跑&#xff0c;怎么办呢&#xff1f; 其实&#xff0c;每次保存的innovus database里面都有专门存放这些数据的文件。我们可以将其中一些setting文件…

VBA技术资料MF197:禁用复制的快捷键

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

Linux内核结构

Linux内核结构 文章目录 Linux内核结构一、Linux内核结构介绍1.1 总体结构&#xff1a;1.2 Linux内核结构框图&#xff1a; 二、图解Linux系统架构三、shell3.1 shell的含义&#xff1a;3.2 shell的作用&#xff1a;3.3 shell的类型&#xff1a;3.4 shell的使用&#xff1a;3.5…

Allow anonymous access to my Azure OpenAI chat bot

题意&#xff1a;允许匿名访问我的 Azure OpenAI 聊天机器人 问题背景&#xff1a; I have an Azure OpenAI chat bot using my own data (I configured an OpenAI resource and chose Deploy as Web App) . Members of my domain can access it by logging in. Now I want it…

2.5 数据库索引机制

我们往数据表里面保存数据记录越来越多&#xff0c;一旦达到上千万条&#xff0c;那怎么提高检索速度就需要认真考虑了。我们打开手机上的APP都希望能快些加载出内容&#xff0c;这里的因素有很多&#xff0c;但是如何减少数据查找的时间是其中的重要一环。索引机制就是提升数据…

【内网渗透】最保姆级的春秋云镜Privilege打靶笔记

目录 flag1 flag2 flag3 flag4 flag1 fscan扫外网 访问./www.zip拿到源码 tools/content-log.php存在任意文件读取 根据提示读到Jenkins初始管理员密码 ./tools/content-log.php?logfile../../../../../../../../../ProgramData/Jenkins/.jenkins/secrets/initialAdminP…

第十一章 【后端】商品分类管理微服务(11.5)——增强响应

11.5 增强响应 在前后端分离的开发模式下,我们一般会统一后端的响应格式,比如自定义 Response 结构,但每个开发者可能会封装各自的 Response 结构,造成不一致,因此我们需要将响应格式统一起来,定义一个统一的标准响应格式。 11.5.1 创建响应模块 新建 yumi-etms-respon…

AJAX Jquery $.get $.post $.getJSON

AJAX AJAX Asynchronous JavaScript and XML (异步的J avascript和XML)。 Ajax $.ajax <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, in…

【Linux进程控制】进程程序替换

目录 进程程序替换 替换函数 看现象 替换原理 多进程替换 exec*函数使用&#xff08;部分&#xff09;&#xff0c;并且认识函数参数的含义 1.execl 2.execv 3.execvp 4.execvpe execlp 和execlpe 替换函数总结 进程程序替换 替换函数 有六种以exec开头的函数&am…

AI大语言模型的全面解读

大语言模型&#xff08;Large Language Models, LLMs&#xff09;无疑是近年来最耀眼的星辰之一。他们以惊人的语言生成能力、上下文理解能力以及对复杂任务的泛化能力&#xff0c;正在深刻改变着自然语言处理&#xff08;NLP&#xff09;乃至整个AI领域的格局。 本文将从专业角…

螺栓与散装物体检测系统源码分享

螺栓与散装物体检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Comput…

代理模式-动态代理

一、代理模式 代理模式:给某一个对象提供一个代理&#xff0c;并由代理对象来控制对真实对象的访问。代理模式是一种结构型设计模式。 代理模式角色分为 3种: Subject(抽象主题角色):定义代理类和真实主题的公共对外方法&#xff0c;通常被设计成接口; RealSubject(真实主题角色…

Flutter 安装,配置,运行第一个app 1

起因&#xff0c; 目的: flutter, 其实几年前&#xff0c;我就写过。 当时纯属是个人兴趣&#xff0c;随意探索。 当时我也写了几篇笔记: 比如这一篇还有这个 flutter&#xff0c;其实不难&#xff0c;比较繁琐&#xff0c;小的知识点很多. flutter&#xff0c; 又是环境配…

如何使用 C# 解决 Cloudflare Turnstile CAPTCHA 挑战

处理 CAPTCHA 挑战的复杂性可能是一项艰巨的任务&#xff0c;尤其是在涉及 Cloudflare 的 Turnstile 时。作为一名经验丰富的开发人员&#xff0c;我多年来遇到了许多 CAPTCHA 系统&#xff0c;但 Cloudflare Turnstile 由于其旨在阻止自动化系统的复杂算法&#xff0c;提出了独…

Mac 搭建仓颉语言开发环境(Cangjie SDK)

文章目录 仓颉编程语言通用版本SDK Beta试用报名仓颉语言文档注册 GitCode登录 GitCode 下载 Cangjie SDK配置环境变量VSCode 插件VSCode 创建项目 仓颉编程语言通用版本SDK Beta试用报名 https://wj.qq.com/s2/14870499/c76f/ 仓颉语言文档 https://developer.huawei.com/c…

ad18学习笔记十七:如何正确打开别人给的工程文件

不要单独打开一个pcb文件&#xff0c;如果没有在一个工程中关联上的话&#xff0c;可能会出现无法复制粘贴焊盘的情况。一般别人给文件会给整个工程&#xff0c;要打开的话直接打开整个工程&#xff0c;那么工程里相互关联的几个文件就都可以操作了。 AD中&#xff0c;怎样把从…

Linux操作系统:GCC(GNU Compiler Collection)编译器

在 Linux 系统中&#xff0c;gcc&#xff08;GNU Compiler Collection&#xff09;是一个非常强大的编译器&#xff0c;主要用于编译 C 语言程序。 除了基本的编译和链接命令外&#xff0c;gcc还提供了许多选项和功能。 以下是一些常用的 gcc命令及其功能&#xff1a; 1. 基本…

WEB攻防-JavaWweb项目JWT身份攻击组件安全访问控制

知识点&#xff1a; 1、JavaWeb常见安全及代码逻辑&#xff1b; 2、目录遍历&身份验证&逻辑&JWT&#xff1b; 3、访问控制&安全组件&越权&三方组件&#xff1b; 演示案例&#xff1a; JavaWeb-WebGoat8靶场搭建使用 安全问题-目录遍历&身份认…