Perl 的 html 解析模块

十二月 29th, 2009

HTML::TreeBuilder
这个解析模块使用了强大的 HTML::Element 模块。解析时,HTML::TreeBuilder模块把整个 html 文档转换成了 perl 的数据结构,可以进行任意的操作。
使用时先创建一个 HTML::TreeBuilder 对象。

use Data::Dumper qw(Dumper);
$Data::Dumper::Indent = 1;
use HTML::TreeBuilder;
my $tree = new HTML::TreeBuilder;

直接向 HTML::TreeBuilder 传递文件好像会把中文转换成 unicode 的字符,所以一般传递文件句柄。而且传递的字符串或者句柄一般要先确保是 utf8 字符串才行,不然会有一个warning:
Parsing of undecoded UTF-8 will give garbage when decoding entities at /home/ywb/temp/t.pl line 16, line 5.
解析文件和解析字符串的区别仅仅是前者是使用 parse_file 函数,而后者使用parse 函数。下面以解析文件句柄的例子:

binmode DATA, “utf8″;
$tree->parse_file(\*DATA);
print Dumper($tree), “\n”;
__DATA__

x y
1 2

要提取出表格中的内容可以这样:

foreach my $row ( $tree->find_by_tag_name(“tr”) ) {
foreach my $cell ( $row->content_list ) {
print $cell->as_text, “\t”;
}
print “\n”;
}

由于 HTML::Element 会强制把所有的 tag 都转换成小写,所以不用担心 tag的大小写问题。HTML::TokenParser和 HTML::Parser 等模块不同,HTML::TokenParser 模块是类似于流(stream oftokens)的方式来解析 HTML 文件。在解析的过程中 HTML 中的文本转换成这六种token:
["S", $tag, $attr, $attrseq, $text]
["E", $tag, $text]
["T", $text, $is_data]
["C", $text]
["D", $text]
["PI", $token0, $text]

这个例子应该能够体现这个模块解析的一些特点:

use HTML::TokeParser;
my $file = \*DATA;
my $parser = HTML::TokeParser->new($file)
or die “Can’t open $file: $!\n”;

my (@table, @row, $inrow);
while (my $token = $parser->get_token( )) {
my $type = $token->[0];
if ( $type eq ‘T’ ) {
push @row, $token->[1] if $inrow;
}
elsif ( $type eq ‘S’ ) {
if ( $token->[1] eq ‘tr’ ) {
$inrow = 1;
}
}
elsif ( $type eq ‘E’ ) {
if ( $token->[1] eq ‘tr’ ) {
push @table, [@row]; # 注意这一行不能用 \@row
@row = ();
$inrow = 0;
}
}
}
print Dumper(\@table), “\n”;

__DATA__

x y
1 2

与前面 HTML::TreeBuilder 的例子相比可能有些麻烦,但是很多情况下,只需要一次处理一个 token,这时候用这个模块就非常方便了,比如你要得到一个html 里所有的图片或者所有的链接,像这样写就行了:

my @images;
while (my $token = $parser->get_token( )) {
my $type = $token->[0];
if ( $type eq ‘S’ ) {
if ( $token->[1] eq ‘img’ ) {
push @images, $token->[2];
}
}
}
__DATA__
Steroidal Camel

专门的模块HTML::LinkExtor如果要提取 html 文件中的链接,也不用自己写了,用 HTML::LinkExtor 就好了。一个简单的例子:

require HTML::LinkExtor;
my $p = HTML::LinkExtor->new();
$p->parse_file(\*DATA);
print Dumper($p->links), “\n”;

__DATA__
x
Steroidal Camel
HTML::LinkExtor 的 new 函数可以提供一个 callback 函数,这个函数是当发现链接时就调用这个函数。传递给这个函数的第一个参数是链接的类型,比如 ‘a’,'img’,其余的参数是链接的属性。如果提供了 callback 函数,HTML::LinkExtor 就不再累积链接了,这意味着你不能再用 links 函数来得到所有的链接。要得到所有链接,只有在 callback 函数里自己保存好。
require HTML::LinkExtor;
my $p = HTML::LinkExtor->new(\&cb);
$p->parse_file(\*DATA);

sub cb {
my($tag, %links) = @_;
print Dumper($tag, \%links), “\n”;
}
__DATA__
x
Steroidal Camel
HTML::HeadParser如果只是要得到 html 的标题或者其它在 head 标签之间内容,就不要用HTML::TreeBuilder 这样的重量级模块了,HTML::HeadParser 模块就能完成这个任务,并且使用相当简单。
require HTML::HeadParser;
my $p = HTML::HeadParser->new;
my $text = join(”, );
$p->parse($text) and print “not finished”;
# to access
print “Title: “, $p->header(‘Title’), “\n”;
# to access
print “Base: “, $p->header(‘Content-Base’), “\n”;
# to access
print “Content type:”, $p->header(‘Content-Type’), “\n”;
# to access
print “Author:”, $p->header(‘X-Meta-Author’), “\n”;
print Dumper($p->header), “\n”;

__DATA__




可以看出它不能解析出 script、link、style 这样的标签。
HTML::TableExtractHTML::TableExtract 只能从 html 中提取出 table 里的内容。如果只要这个,那么这个模块是很容易使用的。
use HTML::TableExtract;
use Data::Dumper qw(Dumper);
my $html_string = join(“”, );
$te = HTML::TableExtract->new();
$te->parse($html_string);
print Dumper($te), “\n”;
foreach $ts ($te->tables) {
print “Table (“, join(‘,’, $ts->coords), “):\n”;
foreach $row ($ts->rows) {
print join(‘,’, @$row), “\n”;
}
}

__DATA__

x y
1 2

由这个例子可以看出,解析后链接信息都丢失了。但是表格里的内容是很容易得到的。

Entry Filed under: program

Leave a Reply

You must be logged in to post a comment.

 

2009年十二月
« 十一   一 »
 123456
78910111213
14151617181920
21222324252627
28293031  

分类目录

标签

书签 优化 参数 命令 啪嗒砰 域名 备份 字体 安装 导入 导出 扩展 换行 文字 正则 爬虫 解决办法 路径 道具 错误 镜像 19楼 Apache awk AWstats CentOS CPAN EditPlus Firefox GD GeoIP Google IBM Linux mysql OUTLOOK Patapon perl photoshop PHP profile rsync sed Shell Thunderbird

最近文章

最近评论

文章索引模板

功能

SEO Powered by Platinum SEO from Techblissonline