0

在我的论坛上,我想自动将rel="nofollow"添加到指向外部站点的链接。例如,有人创建了一个包含以下文本的帖子:

Link 1: <a href="http://www.external1.com" target="_blank">External Link 1</A>
Link 2: <a href="http://www.myforum.com">Local Link 1</A>
Link 3: <a href="http://www.external2.com">External Link 2</A>
Link 4: <a href="http://www.myforum.com/test" ALT="Local">Local Link 2</A>

使用 Perl,我希望将其更改为:

Link 1: <a href="http://www.external1.com" target="_blank" rel="nofollow">External Link 1</A>
Link 2: <a href="http://www.myforum.com">Local Link 1</A>
Link 3: <a href="http://www.external2.com" rel="nofollow">External Link 2</A>
Link 4: <a href="http://www.myforum.com/test" ALT="Local">Local Link 2</A>

我可以使用几行代码来做到这一点,但我希望我可以用一个或多个正则表达式来做到这一点。但我不知道怎么做。

4

2 回答 2

1

正则表达式可以在有限的场景中工作,但你不应该使用正则表达式来解析 HTML

每次您尝试使用正则表达式解析 HTML 时,邪恶的孩子都会流着处女的血,而俄罗斯黑客会破解您的 web 应用程序。

    — 来自RegEx 匹配开放标签,XHTML 自包含标签除外

我非常喜欢 Mojo 套件,因为它允许我们使用非常少的代码使用适当的解析器。我们可以使用 CSS 选择器来寻找有趣的元素:

use strict; use warnings;
use autodie;
use Mojo;
use File::Slurp;

for my $filename (@ARGV) {
  my $dom = Mojo::DOM->new(scalar read_file $filename);

  for my $link ($dom->find('a[href]')->each) {
    $link->attr(rel => 'nofollow')
      if $link->attr('href') !~ m(\Ahttps?://www[.]myforum[.]com(?:/|\z));
  }

  write_file "$filename~", "$dom";
  rename "$filename~" => $filename;
}

调用:perl mark-links-as-nofollow.pl *.html对您的数据运行的测试会产生输出:

Link 1: <a href="http://www.external1.com" rel="nofollow" target="_blank">External Link 1</a>
Link 2: <a href="http://www.myforum.com">Local Link 1</a>
Link 3: <a href="http://www.external2.com" rel="nofollow">External Link 2</a>
Link 4: <a alt="Local" href="http://www.myforum.com/test">Local Link 2</a>

为什么我使用临时文件和rename?在大多数文件系统上,可以自动重命名文件,而写入文件需要一些时间。所以其他进程可能会看到一个写一半的文件。

于 2013-09-04T08:38:41.613 回答
0

我会使用正则表达式 gobal 和 eval 标志进行回调,例如:

#!/usr/bin/perl

use strict;

my $internal_link = qr'href="https?:\/\/(?:www\.)?myforum\.com';

my $html = '
Lorem ipsum
<a href="http://www.external1.com" target="_blank">External Link 1</A>
Lorem ipsum
<a href="http://www.myforum.com">Local Link 1</A>
Lorem ipsum
<a href="http://www.external2.com">External Link 2</A>
Lorem ipsum
<a href="http://www.myforum.com/test" ALT="Local">Local Link 2</A>
';

$html =~ s/<a ([^>]+)>/"<a ". replace_externals($1). ">"/eg;

print $html;

sub replace_externals {
    my ($inner) = @_;
    return $inner =~ $internal_link ? $inner : "$inner rel=\"nofollow\"";
}

或者,您当然可以使用负前瞻,但这只会破坏可读性..

于 2013-09-03T23:02:59.930 回答