如何在Perl中修改HTML文件?

sno*_*kin 1 html perl html-parsing

我有一堆HTML文件,我想要做的是在每个HTML文件中查找关键字'From Argumbay'并使用我拥有的一些href来更改它.起初我觉得它非常简单,所以我做的是打开每个HTML文件并将其内容加载到数组(列表)中,然后我查找每个关键字并将其替换为s ///,并将内容转储到文件,有什么问题?有时关键字也可以出现在href中,在这种情况下我不希望它被替换,或者它可以出现在某些标签内等等.

示例:http://www.astrosociety.org/education/surf.html

我希望我的脚本用$ href中的一些href替换'here'这个单词的每个出现,但正如你所看到的,还有另一个'here'已经是href'ed,我不希望它变成href再来一次.在这种情况下,除了href之外没有其他'这里有',但我们假设有.

我只想更换关键字,只要它只是文字,任何想法?

BOUUNTY编辑:嗨,我相信它很简单,但似乎它删除了HTML,SHTML文件中发现的所有注释(主要问题是它在SHTML中删除了SSI),我尝试使用:store_comments(1)方法调用递归函数之前的$ html,但无济于事.知道我在这里缺少什么吗?

cjm*_*cjm 7

要使用HTML :: TreeBuilder执行此操作,您将读取文件,修改树并将其写出(到同一文件或不同的文件).这相当复杂,因为您尝试将文本节点的一部分转换为标记,并且因为您有无法移动的注释.

HTML-Tree的一个常见习惯是使用修改树的递归函数:

use strict;
use warnings;
use 5.008;

use File::Slurp 'read_file';
use HTML::TreeBuilder;

sub replace_keyword
{
  my $elt = shift;

  return if $elt->is_empty;

  $elt->normalize_content;      # Make sure text is contiguous

  my $content = $elt->content_array_ref;

  for (my $i = 0; $i < @$content; ++$i) {
    if (ref $content->[$i]) {
      # It's a child element, process it recursively:
      replace_keyword($content->[$i])
          unless $content->[$i]->tag eq 'a'; # Don't descend into <a>
    } else {
      # It's text:
      if ($content->[$i] =~ /here/) { # your keyword or regexp here
        $elt->splice_content(
          $i, 1, # Replace this text element with...
          substr($content->[$i], 0, $-[0]), # the pre-match text
          # A hyperlink with the keyword itself:
          [ a => { href => 'http://example.com' },
            substr($content->[$i], $-[0], $+[0] - $-[0]) ],
          substr($content->[$i], $+[0])   # the post-match text
        );
      } # end if text contains keyword
    } # end else text
  } # end for $i in content index
} # end replace_keyword


my $content = read_file('foo.shtml');

# Wrap the SHTML fragment so the comments don't move:
my $html = HTML::TreeBuilder->new;
$html->store_comments(1);
$html->parse("<html><body>$content</body></html>");

my $body = $html->look_down(qw(_tag body));
replace_keyword($body);

# Now strip the wrapper to get the SHTML fragment back:
$content = $body->as_HTML;
$content =~ s!^<body>\n?!!;
$content =~ s!</body>\s*\z!!;

print STDOUT $content; # Replace STDOUT with a suitable filehandle
Run Code Online (Sandbox Code Playgroud)

输出as_HTML将是语法上正确的HTML,但不一定是格式良好的HTML,供人们查看源代码.如果需要,可以使用HTML :: PrettyPrinter写出文件.

  • @ soulSurfer2010,如果要保留注释,则不能使用`new_from_file`,因为你必须调用`store_comments` _before_加​​载文件.相反,调用`new`,然后调用`store_comments`,然后调用`parse_file`. (2认同)