使用Perl中的MyParser从HTML标记中获取内容

时间:2012-11-18 06:32:30

标签: perl html-parsing

我有一个html如下:

<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<body bgcolor="white">

<h1>foo.c</h1>

<form method="post" action=""
        enctype="application/x-www-form-urlencoded">
  Compare this file to the similar file: 
  <select name="file2">

    <option value="...">...</option>


  </select>
  <input type="hidden" name="file1" value="foo.c" /><br>
  Show the results in this format: 
</form>
<hr>

<p>
<pre>
some code
</pre>

我需要获取input name ='file'的值以及HTML pre标签的内容。我不知道perl语言,通过谷歌搜索我写了这个小程序(我相信不是“优雅”):

#!/usr/bin/perl

package MyParser;
use base qw(HTML::Parser);

#Store the file name and contents obtaind from HTML Tags
my($filename, $file_contents);

#This value is set at start() calls
#and use in text() routine..
my($g_tagname, $g_attr);


#Process tag itself and its attributes
sub start {
    my ($self, $tagname, $attr, $attrseq, $origtext) = @_;

    $g_tagname = $tagname;
    $g_attr = $attr;
}

#Process HTML tag body
sub text {
    my ($self, $text) = @_;

    #Gets the filename
    if($g_tagname eq "input" and $g_attr->{'name'} eq "file1") {
    $filename = $attr->{'value'};
    }

    #Gets the filecontents
    if($g_tagname eq "pre") {
    $file_contents = $text;
    }
}

package main;

#read $filename file contents and returns
#note: it works only for text/plain files.
sub read_file {
    my($filename) = @_;
    open FILE, $filename or die $!;
    my ($buf, $data, $n);
    while((read FILE, $data, 256) != 0) {
    $buf .= $data;
    }
    return ($buf);
}


my $curr_filename = $ARGV[0];
my $curr_file_contents = read_file($curr_filename);

my $parser = MyParser->new;
$parser->parse($curr_file_contents);

print "filename: ",$filename,"file contents: ",$file_contents;

然后我致电./foo.pl html.html但我从$filename$file_contents变量获取空值。

如何解决这个问题?

3 个答案:

答案 0 :(得分:6)

与往常一样,有多种方法可以做到这一点。以下是使用DOM Parser Mojolicious执行此任务的方法:

#!/usr/bin/env perl

use strict;
use warnings;
use Mojo::DOM;

# slurp all lines at once into the DOM parser
my $dom = Mojo::DOM->new(do { local $/; <> });

print $dom->at('input[name=file1]')->attr('value');
print $dom->at('pre')->text;

输出:

foo.c
some code

答案 1 :(得分:5)

使用HTML::TreeBuilder::XPath Perl模块(很少行):

#!/usr/bin/env perl
use strict; use warnings;
use HTML::TreeBuilder::XPath;

my $tree = HTML::TreeBuilder::XPath->new_from_content( <> );
print $tree->findvalue( '//input[@name="file1"]/@value' );
print $tree->findvalue( '//pre/text()' );

<强> USAGE

./script.pl file.html

<强>输出

foo.c
some code

备注

  • 过去,我使用HTML::TreeBuilder模块进行网页抓取。现在,我无法回到复杂性。 HTML::TreeBuilder::XPath使用有用的Xpath表达式完成所有魔法。
  • 您可以使用new_from_file方法打开文件或文件句柄而不是new_from_content,请参阅perldoc HTML::TreeBuilderHTML::TreeBuilder::XPath继承HTML::TreeBuilder中的方法)
  • 允许以这种方式使用<>,因为HTML::TreeBuilder::new_from_content()特别允许以这种方式读取多行。大多数构造函数都不允许这种用法。您应该提供标量或使用其他方法。

答案 2 :(得分:4)

除非您编写自己的解析模块或执行一些通常棘手的操作,否则通常不希望使用纯HTML :: Parser。在这种情况下,HTML::TreeBuilder是HTML :: Parser的子类,是最容易使用的。

另外,请注意HTML :: Parser有一个parse_file方法(HTML :: TreeBuilder使用new_from_file方法可以更轻松,因此您不必执行所有这些操作{ {1}}商家(此外,还有比您选择的更好的方法,包括read_file和旧的File::Slurp技巧。

do { local $/; <$handle> }

有关use HTML::TreeBuilder; my $filename = $ARGV[0]; my $tree = HTML::TreeBuilder->new_from_file($filename); my $filename = $tree->look_down( _tag => 'input', type => 'hidden', name => 'file1' )->attr('value'); my $file_contents = $tree->look_down(_tag => 'pre')->as_trimmed_text; print "filename: ",$filename,"file contents: ",$file_contents; look_downattr的信息,请参阅HTML::Element文档; HTML :: TreeBuilder既可以使用,也可以使用元素。