HTML解析庫Gumbo簡單使用記錄


Gumbo簡介

Gumbo是谷歌開源的一個純C編寫的HTML解析庫,性能很好,就是用起來比較麻煩。
github地址https://github.com/google/gumbo-parser
還有一個C++封裝的版本https://github.com/lazytiger/gumbo-query.git

關於HTML的參考,可見https://developer.mozilla.org/zh-CN/docs/Web/HTML

最近准備寫一個爬蟲,用於爬取epsg.io上的數據,所以找了這個庫用於HTML的解析。其實我這個簡單的爬取固定位置的內容,用這個實在是有點殺雞用牛刀了,直接做字符串搜索會更方便。

使用記錄

關於這個的使用,網上找不到太多的資料。
這里有一個https://blog.csdn.net/fjb2080/article/details/78992851

這個圖片上實際已經把相關的關系描述清楚了,我這里只做簡單的補充。

1、GumboNode的類型

對於一個GumboNode結構體對象,需要通過它的GumboNodeType type字段判斷其類型后,可根據類型對成員v進行操作。
v是一個union對象,它可以是GumboDocumentGumboElementGumboText三種類型之一。

1、GUMBO_NODE_DOCUMENT 文檔節點

文檔節點表示的是一個完整的html文檔,就是從<html></html>之間的全部信息。對於v可取GumboDocument類型的成員document
對於文檔節點,其內部包含的元素節點都在GumboVector children中。

2、GUMBO_NODE_ELEMENT 元素節點

只要是含有標簽tag的部分,都是元素節點。這個可以簡單的理解為,只要是<標簽名></標簽名>之間的就是一個元素節點的內容(有的元素是單標簽的),元素節點可以有包含嵌套關系,子節點都在GumboVector children中。

/**
 * 用於表示所有HTML元素的結構。 它包含有關標記,屬性和子節點的信息。
 */
typedef struct {
  /**
   * GumboNodes數組,包含此元素的子元素。 保存的是GumboNode的指針。
   */
  GumboVector /* GumboNode* */ children;

  /** 這個元素的GumboTag(標簽,HTML的標簽是定義好的)枚舉值 */
  GumboTag tag;

  /**  此元素的GumboNamespaceEnum值(表示這個是HTML、SVG還是MATHML)*/
  GumboNamespaceEnum tag_namespace;

  /**
   * 指向此元素的原始標記文本的GumboStringPiece,直接指向源緩沖區。
   * 如果標記是通過算法插入的(例如,<head>或<tbody>插入),則這將是一個零長度字符串。
   */
  GumboStringPiece original_tag;

  /**
   * 指向此元素的原始結束標記文本的GumboStringPiece。
   * 如果以算法方式插入結束標記(例如,關閉自閉標記),則這將是一個零長度字符串。
   */
  GumboStringPiece original_end_tag;

  /** 記錄元素開始標簽在來源字符串中的起始位置。 */
  GumboSourcePosition start_pos;

  /** 記錄元素結束標簽在來源字符串中的起始位置。  */
  GumboSourcePosition end_pos;

  /**
   * GumboAttributes數組,按照解析順序包含此元素標簽的屬性
   * 數組保存的是GumboAttribute的指針
   */
  GumboVector /* GumboAttribute* */ attributes;
} GumboElement;

3、GUMBO_NODE_TEXT 文本節點

文本節點,對於v可取GumboText類型的成員text
Gumbo在解析的時候,對於\r\n這種都會解析為一個獨立的文件節點。

4、GUMBO_NODE_CDATA

CDATA節點是一個比較特殊的節點,這個節點用於傳輸需要瀏覽器不做解析,原封不動的當做文本的內容。所以對於v也是取GumboText類型的成員text

5、GUMBO_NODE_COMMENT

注釋節點,這個用於保存html中的注釋,對於這個節點,對於v也是取GumboText類型的成員text。取出來的GumboText對象中的text成員不包含注釋分隔符

6、GUMBO_NODE_WHITESPACE

這是一個文本節點的特例,文本的內容都是空白字符(空格、TAB、回車)。v也是取GumboText

7、GUMBO_NODE_TEMPLATE

模板節點。就是標簽<template>包含的部分。
這與GUMBO_NODE_ELEMENT是分開的,因為許多客戶端庫都希望忽略模板節點的內容,如規范所示。 在GUMBO_NODE_ELEMENT上遞歸會在這里做正確的事情,而想要包含模板內容的客戶端也應該檢查GUMBO_NODE_TEMPLATE。 v將是一個GumboElement。

2、簡單的使用

為了方便使用,我簡單的封裝了兩個函數,對於我的使用已經足夠了。如果需要更方便的使用,可以考慮https://github.com/lazytiger/gumbo-query.git

1、用於方便一點的查找子節點的

std::vector<GumboNode*> find_sub_node(const GumboNode* parentNode,
	GumboNodeType type, GumboTag tag, int attrCount, ...)
{
	std::vector<GumboNode*> subNode;
	const GumboVector* vec = &(parentNode->v.element.children);
	for (int i = 0; i < vec->length; ++i) {
		GumboNode* node = (GumboNode*)vec->data[i];
		if (node->type != type || (type == GUMBO_NODE_ELEMENT && node->v.element.tag != tag)) {
			continue;
		}
		int pattend = 0;
		va_list vl;
		va_start(vl, attrCount);
		for (int ai = 0; ai < attrCount; ++ai) {
			const char* name = va_arg(vl, char*);
			const char* value = va_arg(vl, char*);
			GumboAttribute* attr = gumbo_get_attribute(&(node->v.element.attributes), name);
			if (attr == NULL || strcmp(value, attr->value) != 0) { continue; }
			pattend += 1;
		}
		va_end(vl);
		if (pattend == attrCount) {
			subNode.push_back(node);
		}
	}

	return subNode;
}

2、用於方便的查找文本子節點的

std::vector<std::string> find_sub_text(const GumboNode* parentNode)
{
	std::vector<std::string> subText;
	const GumboVector* vec = &(parentNode->v.element.children);
	for (int i = 0; i < vec->length; ++i) {
		GumboNode* node = (GumboNode*)vec->data[i];
		if (GUMBO_NODE_TEXT == node->type) {
			subText.push_back(node->v.text.text);
			continue;
		}
	}
	return subText;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM