一个简单的html语法解析函数,一个C++解析HTML的库

HTTP协议使用广泛,相应的,C++在这块需求也开始增加。一个好的解析库可以达到事半功倍的效果,在此贴出我的解析库的代码,方便新手朋友们使用。

hHttpParse.h

#ifndef __H_HTML_PARSE_H__

#define __H_HTML_PARSE_H__

#pragma once

#include

#include

#include

#include

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(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 ("

");

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 ("

hp.SetPos ("

hp.SetPos ("

bool b = true;

if (hp.find (">>")) {

b = false;

hp.SetPos (">>");

hp.MatchString ("%*[^0-9]%[0-9.]", match);

data = match.c_str ();

}

hp.SetPos ("

while (hp.find ("

hp.SetPos (":");

hp.MatchString ("%[^

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(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的网页代码:

您的IP地址
您的IP是:[123.144.*.*] 来自:XX市 联通
地址和位置打码了,大家看得懂就行了。我们先来分析分析,需要获取地址的代码前面有一个
是吧?那就把位置设置在这儿吧。。。

4、设置当前解析位置

hp.SetPos ("

");在这个解析库内部维护着一个字符指针,假如说网页前面的都解析过了,需要解析后面的,那就在解析时给字符指针赋值,然后下次解析时从字符指针位置开始解析,既方便网页处理,也提高解析速度,一举两得。这行代码的意思就是将内部维护的地址放在
这儿,下次调用时直接从这儿开始了。

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(s.c_str()) 赋值(这行代码可以在 hHtmlParse::MatchString 函数中找到),所以,在执行步骤6这段代码前,调用 match.length() 实际上返回的是不固定值,虽然不固定但是有数据。所以,假如非得在 const_cast(s.c_str()) 之后获取字符串长度,只能用lstrlen。

这几行代码大家应该都懂,简要说说第二行,意思是调用 std::string 的重载函数 operator=(char*) ,这样可以刷新 std::string 的长度,执行第二行代码之后,ip中的数据可以直接调用 length() 来获取长度了。 使用步骤描述完毕,同学们如果需要解析其他网页在相应地方修改就行了。另外, SetPos 和 MatchString 并不是只能调用一次的,只要找网页方便,并且保证对象内部维护的指针还没到末尾,就可以重复调用这些函数了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值