如何运用C语言读取任意一个html

html-css09

如何运用C语言读取任意一个html,第1张

1. 首先定义一个File 的变量

2.然后用

FILE *fopen(

const char *filename,

const char *mode

)

这个函数读入 html 文件

3.用这个读入文件内容

size_t fread(

void *buffer,

size_t size,

size_t count,

FILE *stream

)

4.之后进行字符数组的处理

不行, 只有脚本式语言才能嵌入HTML.

C语言是编译后才能运行的语言,不能嵌入HTML.

CGI -- Common Gateway Interface 接口程序是另一概念,它用于服务器端,在服务器控制下,处理来自流览器<FORM ..>... </FORM>的输入信息,再输出动态网页.CGI程序可以用脚本式语言,也可用C. C程序是编译后用的,不是嵌入式.CGI程序是生产出HTML.

嵌入式,例如PHP,ASP,是服务器端用的,javascript是客户端用的.嵌入式是脚本式语言的混合.通过各自的解释器解释执行.

之前使用过PHP的Simple HTML DOM简单地解析HTML但PHP终非我所熟悉的语言,虽然我并不对语言抱有绝对的执着= =(什么你不相信,好吧,不管你信不信,反正我是信了= =)。虽然可以简单地使用正则表达式来解析HTML但我不是希望能够找到一个合适的HTML解析库,网上搜索了下关于c语言解析HTML的库,好像不是挻多的样子,我搜索到了google的gumbo,

gumbo是开源的,可以从这里得到它

https://github.com/google/gumbo-parser

我们需要下载回来手动编译安装,这里以linux debian为例

git clone https://github.com/google/gumbo-parser

cd gumbo-parser

./autogen.sh

./configure

这些一般都会非常顺利,没什么好说的,接下来就是

make

我要执行make后发现有一个错误导致无法编译通过,不知道各位是什么情况,给出的错误提示是benchmarks/benchmark.cc

文件中使用了未定义的函数clock_gettime

man了一下,该函数需要包含time.h头文件,打开benchmark.cc文件查看的确已经包含了time.h头文件,很苦恼,突然一下子就懵了,不过还好我反应还算快,看到manpages中写到

Link with -lrt (only for glibc versions before 2.17).

于是猜测没有链接库,使用vim打开Makefile文件,这个文件内容太多= =,要分析的话有些费劲,不过机智的我还是很快地通过benchmark关键字定位到了benchmark_LDADD这个变量,然后在后面加上

-lrt

注意有空格

再次make,果然成功了。。。。。。。。。。。

编译完成之后就可以使用make install进行安装了,你可能需要使用root用户权限,因为默认的安装目录在/usr/local/下

gumbo的源码提供了几个示例程序,一个c语言写的获取标题的源码和另外三个使用c++编写的代码,我全都看了(你看,我说过我不是绝对的语言执着者吧,很不幸,这些程序我都看懂了= =)

简单地说gumbo的使用很简单,使用gumbo_parse或者gumbo_parse_with_options就可以得到一个GumboOutput数据结构,我们就可以从该结构中寻找我们想要的东西了。

我们先来看一个简单的例子,就拿获取title来说吧,我决定用自己写的解析代码而不是gumbo源码提供的好个示例,因为我发现该程序无法解析出我使用的示例HTML文本文件= =,所以我就自己写个吧。。。。。。

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <stdlib.h>

#include <string.h>

/* 包含头文件 */

#include <gumbo.h>

void get_title(GumboNode *node)

{

GumboVector *children

int i

/* 如果当前节点不是一个元素的话直接返回 */

if(node->type != GUMBO_NODE_ELEMENT) return

/* 获取该节点的所有子元素节点 */

children=&node->v.element.children

/* 检查当前节点的标签是否为TITLE(title)

* 如果是则输出该节点下第一个节点的文本内容 */

if(node->v.element.tag == GUMBO_TAG_TITLE)

printf("%s\n",((GumboNode *)children->data[0])->v.text.text)

/* 递归该节点下的所有子节点 */

for(i=0i <children->length++i)

get_title(children->data[i])

}

int main(int argc,char **argv)

{

struct stat buf

GumboOutput *output

FILE *fp

char *data

/* 读取HTML文本文件 */

if(!(fp=fopen(argv[1],"rb"))) return -1

stat(argv[1],&buf)

data=malloc(sizeof(char)*(buf.st_size+1))

fread(data,sizeof(char),buf.st_size,fp)

fclose(fp)

data[buf.st_size]=0

/* 解析HTML文本文件 */

output=gumbo_parse(data)

/* 获取TITLE */

get_title(output->root)

/* 销毁,释放内存 */

gumbo_destroy_output(&kGumboDefaultOptions,output)

free(data)

return 0

}

注释已经写的很清楚了,首先我们的节奏是这个样子的:

第一步加载HTML文本文件,我们把它读到一个buf中,

第二步我们进行解析出GumboOutput数据结构

第三步在GumboOptout这个数据结构中找出title标签

最后我们输出内容,gumbo的步骤基本上就是这个样子的了,使用gcc编译的时候需要加上

-lgumbo

下面再说一个例子,该例子中的HTML文件内容是各国DNS的IP地址以及物理地址,大概的格式是

<dt><dd class="ipstart">开始ip地址</dd><dd class="ipend">结束ip地址</dd><dd class="address">物理地址</dd></dt>

我们的解析步骤是获取所有dt标签再获取所有dd标签,然后分别输出dd标签中class属性为ipstart、ipend、address的内 容,下面放代码,由于原HTML文本文件内容放多,我不便放上来,这里就使用在线抓取的方式获取HTML文本,所以这里给出的是HTML文本的url地 址,至目前写代码这一刻该程序还是完全能够正常工作的,日后会该网页是否会因该网页做调整等原因解析出错就不得而知了。

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <oauth.h>

/* 包含头文件 */

#include <gumbo.h>

#define URL "http://ip.yqie.com/dns_usa.htm"

void print_dns(GumboNode *node,GumboAttribute *attr)

{

/* 获取子节点 */

GumboNode *ip=(GumboNode *)(&node->v.element.children)->data[0]

/* 根据class属性的值打印结果 */

if(strcmp(attr->value,"ipstart") == 0)

{

if(ip->type == GUMBO_NODE_TEXT)

printf("开始IP:%s ",ip->v.text.text)

}

else if(strcmp(attr->value,"ipend") == 0)

{

if(ip->type == GUMBO_NODE_TEXT)

printf("结束IP:%s ",ip->v.text.text)

}

else if(strcmp(attr->value,"address") == 0)

{

if(ip->type == GUMBO_NODE_TEXT)

printf("物理地址:%s\n",ip->v.text.text)

}

}

void get_dns(GumboNode *node,GumboTag tag)

{

GumboVector *children

GumboAttribute *attr

int i

if(node->type != GUMBO_NODE_ELEMENT) return

/* 获取当前节点class属性 */

if(attr=gumbo_get_attribute(&node->v.element.attributes,"class"))

print_dns(node,attr)

/* 当前节点子节点 */

children=&node->v.element.children

/* 如果当前节点标签为td我们就查找dd标签 */

if(node->v.element.tag == GUMBO_TAG_DT)

for(i=0i <children->length++i)

get_dns(children->data[i],GUMBO_TAG_DD)

/* 查找所有<dt>标签 */

for(i=0i <children->length++i)

get_dns(children->data[i],GUMBO_TAG_DT)

}

int main(void)

{

GumboOutput *output

char *buf

/* 下载HTML文本文件 */

buf=oauth_http_get(URL,NULL)

if(!buf) return-1

/* 解析 */

output=gumbo_parse(buf)

if(!output)

{

free(buf)

return -1

}

/* 获取我们想要的内容 <dt>*/

get_dns(output->root,GUMBO_TAG_DT)

/* 释放资源 */

gumbo_destroy_output(&kGumboDefaultOptions,output)

free(buf)

return 0

}