1. 程式人生 > >一個C++解析HTML的庫

一個C++解析HTML的庫

HTTP協議使用廣泛,相應的,C++在這塊需求也開始增加。一個好的解析庫可以達到事半功倍的效果,在此貼出我的解析庫的程式碼,方便新手朋友們使用。

hHttpParse.h

#ifndef __H_HTML_PARSE_H__
#define __H_HTML_PARSE_H__

#pragma once

#include <Windows.h>
#include <WinInet.h>
#include <string>
#include <cstdio>

class hHtmlParse {
	std::string data;
	int p;
public:
	//建構函式,傳入HTML程式碼
	hHtmlParse (std::string& data);
	//獲取網頁的編碼方式
	bool GetCharset (std::string& s);
	//設定當前解析位置
	bool SetPos (const char* find);
	//設定當前解析位置(反向查詢目標位置)
	bool SetPos_LastOf (const char* find);
	//查詢是否存在目標位置,不會更新當前位置
	bool find (const char* find);
	//匹配一串字串,使用sscanf_s獲取
	bool MatchString (const char* match, std::string& s);
	//獲取當前電腦IP地址
	static bool GetLocalIp (std::string& ip);
	//查詢某地址或某域名資訊
	static bool GetAddrMessage (const wchar_t* addr, std::string& data);
	//關鍵函式,獲取lpURL指向的地址的HTML程式碼,並存入data中
	static bool UrlGetHtml (LPCWSTR lpURL, std::string& data);
};

#endif //__H_HTML_PARSE_H__


hHttpParse.cpp
#include "hHtmlParse.h"

#pragma comment(lib, "WinInet.lib")

hHtmlParse::hHtmlParse (std::string& data) {
	this->data = data;
	this->p = 0;
}

bool hHtmlParse::GetCharset (std::string& s) {
	this->SetPos ("charset=");
	return this->MatchString ("%*[\"]%[^\"]", s);
}

bool hHtmlParse::SetPos (const char* find) {
	int t = this->data.find (find, p);
	if (-1 == t) return false;
	this->p = t + strlen (find);
	return true;
}

bool hHtmlParse::SetPos_LastOf (const char* find) {
	int t = this->data.rfind (find);
	if (-1 == t) return false;
	this->p = t + strlen (find);
	return true;
}

bool hHtmlParse::find (const char* find) {
	int t = this->data.find (find, p);
	return t != -1;
}

bool hHtmlParse::MatchString (const char* match, std::string& s) {
	return sscanf_s (&data.c_str () [p], match, const_cast<char*>(s.c_str ()), s.capacity ()) > 0;
}

bool hHtmlParse::GetLocalIp (std::string& ip) {
	std::string page, match;
	page.resize (512);
	match.resize(16);
	if (!hHtmlParse::UrlGetHtml (L"http://1111.ip138.com/ic.asp", page)) return false;
	hHtmlParse hp (page);
	hp.SetPos ("<center>");
	hp.MatchString ("%*[^0-9]%[0-9.]", match);
	ip.clear ();
	ip = match.c_str ();
	return true;
}

bool hHtmlParse::GetAddrMessage (const wchar_t* addr, std::string& data) {
	data.clear ();
	std::wstring link = L"http://www.ip138.com/ips138.asp?ip=";
	std::string page, match;
	link += addr;
	page.resize (16384);
	match.resize (64);
	if (!hHtmlParse::UrlGetHtml (link.c_str (), page)) return false;
	hHtmlParse hp (page);
	hp.SetPos_LastOf ("<table");
	hp.SetPos ("<td");
	hp.SetPos ("<td");
	bool b = true;
	if (hp.find (">>")) {
		b = false;
		hp.SetPos (">>");
		hp.MatchString ("%*[^0-9]%[0-9.]", match);
		data = match.c_str ();
	}
	hp.SetPos ("<ul");
	while (hp.find ("<li")) {
		hp.SetPos (":");
		hp.MatchString ("%[^<]", match);
		if (b) b = false; else data += "\n";
		data += match.c_str ();
	}
	return true;
}

bool hHtmlParse::UrlGetHtml (LPCWSTR lpURL, std::string& data) {
	HINTERNET hSession = InternetOpenW (L"EmotionSniffer", NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE);
	if (!hSession) return FALSE;
	HINTERNET hFile = InternetOpenUrlW (hSession, lpURL, NULL, NULL, INTERNET_FLAG_RELOAD, NULL);
	if (!hFile) {
		InternetCloseHandle (hSession); return FALSE;
	}
	DWORD dwW = 0, dwR = 0;
	int capacity = data.capacity ();
	do {
		dwW += dwR;
		if (dwW != 0 && dwR == 0) break;
		if (dwW + 1024 >= capacity) data.resize (capacity *= 2);
	} while (InternetReadFile (hFile, (LPVOID) (data.c_str () + dwW), 1024, &dwR));
	const_cast<char*>(data.c_str ()) [dwW] = '\0';
	InternetCloseHandle (hFile);
	InternetCloseHandle (hSession);
	return TRUE;
}

簡要說明下使用方法。首先是封裝的三個靜態函式, GetLocalIp 和 GetAddrMessage 這倆是通過呼叫 www.ip138.com 動態查詢獲取的結果,呼叫這個庫實現。使用這個庫時可以參照上面兩個函式的程式碼; UrlGetHtml 是通過 Windows 的 Internet API 實現從 URL 指定的地址下載網頁。

重點說說這個庫的使用方法,我就說說 hHtmlParse::GetLocalIp 則函式的實現,方法大多類似。

1、字串定義

std::string page, match;
page.resize (512);
match.resize (16);

其中 page 用作儲存 HTML 程式碼, match 用作儲存匹配的字串,也就是網頁中需要獲取的資料。由於訪問的資料不大,所以 page 設定 512 位元組足夠。這兒也可以不用設定大小的, UrlGetHtml 實現的比較智慧,可以自動擴充套件大小。設定一個大小隻是可以減少記憶體 I/O ,提高執行速度。另外這兒也給 match 設定一個大小。對於IP地址來說,16位元組足夠了。

2、獲取網頁HTML程式碼

if (!hHtmlParse::UrlGetHtml (L"http://1111.ip138.com/ic.asp", page)) return false;
這句話的意思就是下載網頁並將網頁程式碼儲存在 page 中,如果執行失敗則返回。

3、建立解析物件

hHtmlParse hp (page);
這句程式碼用於建立一個解析物件,傳入的資料為網頁HTML字串。
這裡我們看看ip138的網頁程式碼:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=gb2312">
<title> 您的IP地址 </title>
</head>
<body style="margin:0px"><center>您的IP是:[123.144.*.*] 來自:XX市 聯通</center></body></html>
地址和位置打碼了,大家看得懂就行了。我們先來分析分析,需要獲取地址的程式碼前面有一個 <center> 是吧?那就把位置設定在這兒吧。。。
4、設定當前解析位置
hp.SetPos ("<center>");
在這個解析庫內部維護著一個字元指標,假如說網頁前面的都解析過了,需要解析後面的,那就在解析時給字元指標賦值,然後下次解析時從字元指標位置開始解析,既方便網頁處理,也提高解析速度,一舉兩得。這行程式碼的意思就是將內部維護的地址放在 <center> 這兒,下次呼叫時直接從這兒開始了。

5、獲取匹配字串,也就是IP地址

hp.MatchString ("%*[^0-9]%[0-9.]", match);
這兒就是獲取匹配字串的程式碼了 ,第一個引數為sscanf函式需要的那個字串,match返回匹配的結果。簡要說說這個字串的意思,需要深究的自行bing。

%*[^0-9]   %*表示跳過,不匹配,[]表示匹配的內容,^表示非,0-9表示那十個數字。連起來的意思就是跳過所有不是0-9的字元。

%[0-9.]   %表示匹配,0-9.表示匹配的內容為那十個數字和小數點,一直到非0-9或小數點為止。

程式碼到這兒就已經獲取了匹配的ip了,接下來的內容就是簡單的處理了。

6、簡單處理並返回

ip.clear ();
ip = match.c_str ();
return true;

由於匹配是通過 const_cast<char*>(s.c_str()) 賦值(這行程式碼可以在 hHtmlParse::MatchString 函式中找到),所以,在執行步驟6這段程式碼前,呼叫 match.length() 實際上返回的是不固定值,雖然不固定但是有資料。所以,假如非得在 const_cast<char*>(s.c_str()) 之後獲取字串長度,只能用lstrlen。

這幾行程式碼大家應該都懂,簡要說說第二行,意思是呼叫 std::string 的過載函式 operator=(char*) ,這樣可以重新整理 std::string 的長度,執行第二行程式碼之後,ip中的資料可以直接呼叫 length() 來獲取長度了。

使用步驟描述完畢,同學們如果需要解析其他網頁在相應地方修改就行了。另外, SetPos 和 MatchString 並不是只能呼叫一次的,只要找網頁方便,並且保證物件內部維護的指標還沒到末尾,就可以重複呼叫這些函數了。

相關推薦

一個C++解析HTML

HTTP協議使用廣泛,相應的,C++在這塊需求也開始增加。一個好的解析庫可以達到事半功倍的效果,在此貼出我的解析庫的程式碼,方便新手朋友們使用。 hHttpParse.h #ifndef __H_HTML_PARSE_H__ #define __H_HTML_PARSE_

C# 解析html中篩選class的問題

help get 是否 sans tags pan key 似的 vertica C# 解析html中篩選class的問題C# html解析 class 類 當我們用C#的.net解析html的時候,當html的元素沒有id,並且沒有過多的屬性供篩選,只能通過class

C#解析html文件

當我們需要解析一個web頁面的時候,如果非常簡單,可以用字串查詢的方式,複雜一點可以用正則表示式,但是有時候正則很麻煩的,因為html程式碼本身就比較麻煩,像常用的img標籤,這個東東到了瀏覽器上就沒了閉合標籤(一直還沒搞懂為什麼),想用XML解析,也是同樣的原因根本解析

介紹C#解析HTML的兩種方法

在搜尋引擎的開發中,我們需要對網頁的Html內容進行檢索,難免的就需要對Html進行解析。拆分每一個節點並且獲取節點間的內容。此文介紹兩種C#解析Html的方法。     C#解析Html的第一種方法:     用System.Net.WebClient下載Web Page存到本地檔案或者String中,用

迫不及待推薦一個C++計算幾何

怎麼發現的 有事沒事就喜歡找一些感興趣的問題,然後循著問題中的答案或相關的引用到處漫遊,點連結或者偶爾放狗搜一下,然後就找到這個地方了: 謹慎使用: 這個庫應該是不錯的;但是感覺缺乏Eigen那樣嚴格的程式碼的peer review機制和大量而有效的測試

C#解析HTML

在搜尋引擎的開發中,我們需要對網頁的Html內容進行檢索,難免的就需要對Html進行解析。拆分每一個節點並且獲取節點間的內容。此文介紹兩種C#解析Html的方法。第一種方法: 用System.Net.WebClient下載Web Page存到本地檔案或者String中,用正則表示式來分析。這個方法可以用在We

mlpack: 一個C++機器學習

簡介 mlpack是一個C++機器學習庫,側重於可擴充套件性、速度和易用性。它的目的是通過一個簡單的、前後一致的API讓新使用

使用C#和HtmlAgilityPack解析HTML

load() 需要 有一個 Coding -c href .net tar doc   近期,有一個需求,需要解析HTML頁面,讀取一些需要的數據後,插入本地數據庫。我知道可以通過正則表達式實現,然而正則表達式之於我,就像匯編語言之於我,一樣。我知道它是幹什麽的,我也知道它

C/C++使用libcurl發送http請求(get和post可以用於請求html信息,也可以請求xml和json等串)

網絡連接 get 編譯 eas views vs2015 return tar linux C++要實現http網絡連接,需要借助第三方庫,libcurl使用起來還是很方便的 環境:win32 + vs2015 如果要在Linux下使用,基本同理 1,下載

php解析htmlsimple_html_dom

響應 過多 echo 記得 正則 下載 int curl sse 下載地址:https://github.com/samacs/simple_html_dom解析器不僅僅只是幫助我們驗證html文檔;更能解析不符合W3C標準的html文檔。它使用了類似jQuery的元素選擇

C# 網絡爬蟲利器之Html Agility Pack如何快速實現解析Html

mlp get 設計 navig send 介紹 sca 元素 對象 簡介   現在越來越多的場景需要我們使用網絡爬蟲,抓取相關數據便於我們使用,今天我們要講的主角Html Agility Pack是在爬取的過程當中,能夠高效的解析我們抓取到的html數據。 優勢   在.

python解析HTML之:PyQuery的介紹與使用

att 用法 hello ext dom 的人 inf 目標 title 本篇大部分轉載於https://www.jianshu.com/p/c07f7cd1b548 先放自已自己解析techweb一個網站圖片的代碼 from pyquery import PyQuery

使用C++解析MNIST數據

可視化 win 大坑 fop 存儲 ring ios num 出了 遇到的兩個個大坑 1.官方主頁給出了每個文件的字節數是個玄幻數據,training set images (9912422 bytes) ,這個字節數是解壓前的,解壓後字節數應該為47,040,016,這個

HTML 解析HtmlAgilityPack

html解析 類型 dht 好的 cts 布爾 repos 通過 節點 1. HtmlAgilityPack簡介 網站中首先遇到的問題是爬蟲和解析HTML的問題,一般情況在獲取頁面少量信息的情況下,我們可以使用正則來精確匹配目標。不過本身正則表達式就比較復雜,同時正

關於怎麽在VS2017中建立一個C/C++函數

and 函數 動態鏈接 mic view microsoft 自己 uil lin 想起來自己在大一暑假時做過飛機大戰的小遊戲,於是選擇在VS中創建一個自己的動態鏈接庫(C++),也是為了將加強自己對於數據結構的鞏固。 因為自己也是第一次接觸,於是百度來

Android解析Html,快速打造一個App

轉載請註明出處:http://blog.csdn.net/xiaoyuan511 歡迎訪問:程式設計師自己的導航網站—極客導航 一、概述 我們都知道大部分後端返回給移動端的資料都是以Json資料返回的。有些時候如果我想直接顯示網頁上資料怎麼辦呢。可能我們都知道直接

Java開源Html解析(轉載)

  NekoHTML  NekoHTML是一個簡單地HTML掃描器和標籤補償器(tag balancer) ,使得程式能解析HTML文件並用標準的XML介面來訪問其中的資訊。這個解析器能投掃描HTML檔案並“修正”許多作者(人或機器)

關於 C#呼叫一個C/C++dll執行時實現多個應用(靜態變數區分) 的解決方法

需求         VS編寫了純C(windows)通訊庫,需要多例項(靜態變數標誌一個例項,達到互相靜態變數不干涉)。   當前問題         dll中使用了全域性static的標

安利個人開發維護的一個C++模板(沒有三方依賴, 純標頭檔案) oyoungs/dispatch

專案倉庫地址 C++模板庫oyoungs/dispatch介紹 這是個人開發維護的一個工具性質的純標頭檔案的C++庫 內容包括 dispatch.hpp 同步/非同步排程任務佇列, async

利用C語言標準生成一個真隨機數的方法

        首先需要明確一點的是,計算機系統中生成一個隨機數,需要依賴一個隨機量,這個隨機量稱為隨機數種子。否則生成的就是偽隨機數。隨機數種子的值越多樣化,生成的數就越隨機。通常,隨機數種子從計算機系統外部引入,例如人的操作、ADC採集到的值等。         C語言