Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Perl在HTML中查找favicon_Perl_Favicon_Www Mechanize - Fatal编程技术网

使用Perl在HTML中查找favicon

使用Perl在HTML中查找favicon,perl,favicon,www-mechanize,Perl,Favicon,Www Mechanize,我试图使用Perl为给定URL寻找favicon(和变体)(我希望避免使用外部服务,如Google的favicon finder)。有一个CPAN模块,WWW::Favicon,但它已经十多年没有更新了——在这十年中,像“苹果触摸图标”这样的重要变体已经取代了久负盛名的“ico”文件 我想我在WWW::Mechanize中找到了解决方案,因为它可以列出给定URL中的所有链接,包括标题标记。但是,我似乎找不到一个干净的方法来使用“find_link”方法搜索rel属性 例如,我尝试使用“rel”作

我试图使用Perl为给定URL寻找favicon(和变体)(我希望避免使用外部服务,如Google的favicon finder)。有一个CPAN模块,WWW::Favicon,但它已经十多年没有更新了——在这十年中,像“苹果触摸图标”这样的重要变体已经取代了久负盛名的“ico”文件

我想我在WWW::Mechanize中找到了解决方案,因为它可以列出给定URL中的所有链接,包括
标题标记。但是,我似乎找不到一个干净的方法来使用“find_link”方法搜索
rel
属性

例如,我尝试使用“rel”作为搜索词,希望它可能在那里,尽管文档中没有提到,但它不起作用。此代码返回一个关于无效“链接查找参数”的错误

我还尝试使用其他链接查找参数,但它们似乎都不适合搜索rel属性

我能找到的唯一方法是遍历所有链接并查找如下rel属性:

my $results = $mech->find_all_links(  );

foreach my $result (@{ $results }) {
    my $attrs = $result->attrs();
    #'tag' => "apple-touch-icon"
    
    foreach my $attr (sort keys %{ $attrs }) {
        if ($attrs->{'rel'} =~ /^apple-touch-icon.*$/) {
            say STDERR "I found it:" . $result->url();
        }

        # Add tests for other types of icons here.
        # E.g. "mask-icon" and "shortcut icon."

    }

}

这是可行的,但看起来很混乱。有更好的方法吗?

这个问题很容易解决:

  • 允许加载网页的任何模块的帮助
  • 为所有可能的favicon变体定义
    $regex
  • 查找
注: 脚本在代码中嵌入了默认的YouTubeurl

use strict;
use warnings;
use feature 'say';

use HTTP::Tiny;

my $url = shift || 'https://www.youtube.com/';

my $icons = get_favicon($url);

say for @{$icons};

sub get_favicon {
    my $url = shift;
    
    my @lookup = (
                    'shortcut icon',
                    'apple-touch-icon',
                    'image_src',
                    'icon',
                    'alternative icon'
                );
                
    my $re      = join('|',@lookup);
    my $html    = load_page($url);
    my @icons   = ($html =~ /<link rel="(?:$re)" href="(.*?)"/gmsi);
    
    return \@icons;
}

sub load_page {
    my $url = shift;
    
    my $response = HTTP::Tiny->new->get($url);
    my $html;

    if ($response->{success}) {
        $html = $response->{content};
    } else {
        say 'ERROR:  Could not extract webpage';
        say 'Status: ' . $response->{status};
        say 'Reason: ' . $response->{reason};
        exit;
    }

    return $html;
}
作为
script.pl”运行http://www.microsoft.com/“

作为
script.pl”运行http://finance.yahoo.com/“

这是我用它的方法。获取HTML页面后,使用
dom
执行所有解析。在此基础上,使用CSS选择器查找感兴趣的节点:

link[rel*=icon i][href]
此CSS选择器查找同时具有
rel
href
标记的
link
标记。此外,我要求
rel
中的值包含(
*=
)“icon”,不区分大小写(即
I
)。如果您想假设所有节点都有
href
,只需关闭
[href]

有了链接列表后,我只提取
href
中的值,并将该列表转换为数组引用(尽管我可以使用
Mojo::Collection
方法完成其余操作):

到目前为止效果相当不错:

$ perl mojo.pl https://www.perl.org
https://cdn.perl.org/perlweb/favicon.ico

$ perl mojo.pl https://www.microsoft.com
https://c.s-microsoft.com/favicon.ico?v2

$ perl mojo.pl https://leanpub.com/mojo_web_clients
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/apple-touch-icon-57x57-b83f183ad6b00aa74d8e692126c7017e.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/apple-touch-icon-60x60-6dc1c10b7145a2f1156af5b798565268.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/apple-touch-icon-72x72-5037b667b6f7a8d5ba8c4ffb4a62ec2d.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/apple-touch-icon-76x76-57860ca8a817754d2861e8d0ef943b23.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/apple-touch-icon-114x114-27f9c42684f2a77945643b35b28df6e3.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/apple-touch-icon-120x120-3819f03d1bad1584719af0212396a6fc.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/apple-touch-icon-144x144-a79479b4595dc7ca2f3e6f5b962d16fd.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/apple-touch-icon-152x152-aafe015ef1c22234133158a89b29daf5.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/favicon-16x16-c1207cd2f3a20fd50de0e585b4b307a3.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/favicon-32x32-e9b1d6ef3d96ed8918c54316cdea011f.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/favicon-96x96-842fcd3e7786576fc20d38bbf94837fc.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/favicon-128x128-e97066b91cc21b104c63bc7530ff819f.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/favicon-196x196-b8cab44cf725c4fa0aafdbd237cdc4ed.png
现在,如果您发现了更有趣的案例,并且无法轻松编写选择器,那么问题就来了。假设并非所有的
rel
值中都有“icon”。您可以通过指定多个由逗号分隔的选择器来获得更多的乐趣,这样您就不必使用实验性案例不敏感标志:

link[rel*=icon][href], link[rel*=ICON][href]
rel
中的不同值:

link[rel="shortcut icon"][href], link[rel="apple-touch-icon-precomposed"][href]
尽可能多地排队

但是,您也可以在不使用选择器的情况下过滤结果。使用Mojo::Collection的
grep
选择您想要的节点:

my %Interesting = ...;
my $results = $ua->get( shift )
    ->result
    ->dom
    ->find( '...' )
    ->grep( sub { exists $Interesting{ $_->attr('rel') } } )
    ->map( attr => 'href' )
    ->to_array
    ;

我在中有更多的
Mojo::DOM
示例,我想现在就添加这个示例。

用正则表达式“解析”HTML有点脆弱。我喜欢OP关于更好地使用WWW::Mechanize的想法。但是,您的代码有更多可能的文件名。也许最好合并这两种方法。@Robert,PB暗示使用正确的解析会更复杂,这是胡说八道——它通常比正则表达式的替代方法要简单——但它们确实有道理。生成不正确内容的正则表达式被破坏的风险很低。而且它可能比使用一个合适的HTML解析器更快……或者会更快?谢谢大家@PolarBear的方法看起来确实比我的简单,尽管我确实喜欢WWW::Mechanize的弹性。例如,如果一个格式稍差的站点反转了rel和href属性,该怎么办?(顺便说一句,也许这在技术上并不是无效的。)也许可以选择使用正则表达式拆分所有属性的名称/值对,然后对它们进行分析,使其不依赖于特定的顺序?在这一点上,坚持使用WWW::Mechanize是否更好?在Mojo::UA中使用类似于Mojo::DOM的解析器应该可以很好地工作。我快速浏览了WWW::Favicon模块。找到了它的github,它有一个5年历史的PR尚未合并,但维护者在CPAN上拥有40多个Dist,最新版本为2018年,并且他的github不是不活跃的。我可以给他发消息并接管模块。这段代码要求HTML采用特定的形式。这是个坏主意。你说的机械化不能做到这一点是正确的。我通过rel创建了一个过滤器。谢谢@simbabque!如果他们添加了这个选项,Mechanize似乎会更适合这种情况。brian的解决方案很棒。我同意。但我想我们还是会将它添加到Mechanize中(免责声明:我是维护贡献者之一)。感谢@simbabque为Mechanize所做的工作——我很高兴能遇到它。我正在使用我最初的黑客方法,至少在我弄清楚如何做我在Brian的答案评论中讨论的事情之前。如果它有你在公共关系中所做的,它真的会工作得很好。我会试试看,谢谢!也许我应该把它写成一个答案,并在这里分享。谢谢,@briandfoy!如果我想分几部分进行分析,有没有好的方法?例如,如果两者都存在,我可能更喜欢“apple touch图标预合成”而不是“favicon-16x16”。我以前没有玩过Mojolicious——语法看起来有点不同。我可以在map中要求两个属性吗(例如rel是什么和href)?您可以在
map
中做任何您喜欢的事情。这确实是
map(sub{…})
的快捷方式,项目位于sub中的
$\uu
中。我想我开始流行起来了。因此,
map
中的匿名子例程可以查看
$的不同部分以及它们的输出?
到_数组
期望从该子例程得到什么格式?能够
use v5.10;

use Mojo::UserAgent;
my $ua = Mojo::UserAgent->new->max_redirects(3);

my $results = $ua->get( shift )
    ->result
    ->dom
    ->find( 'link[rel*=icon i][href]' )
    ->map( attr => 'href' )
    ->to_array
    ;

say join "\n", @$results;
$ perl mojo.pl https://www.perl.org
https://cdn.perl.org/perlweb/favicon.ico

$ perl mojo.pl https://www.microsoft.com
https://c.s-microsoft.com/favicon.ico?v2

$ perl mojo.pl https://leanpub.com/mojo_web_clients
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/apple-touch-icon-57x57-b83f183ad6b00aa74d8e692126c7017e.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/apple-touch-icon-60x60-6dc1c10b7145a2f1156af5b798565268.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/apple-touch-icon-72x72-5037b667b6f7a8d5ba8c4ffb4a62ec2d.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/apple-touch-icon-76x76-57860ca8a817754d2861e8d0ef943b23.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/apple-touch-icon-114x114-27f9c42684f2a77945643b35b28df6e3.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/apple-touch-icon-120x120-3819f03d1bad1584719af0212396a6fc.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/apple-touch-icon-144x144-a79479b4595dc7ca2f3e6f5b962d16fd.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/apple-touch-icon-152x152-aafe015ef1c22234133158a89b29daf5.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/favicon-16x16-c1207cd2f3a20fd50de0e585b4b307a3.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/favicon-32x32-e9b1d6ef3d96ed8918c54316cdea011f.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/favicon-96x96-842fcd3e7786576fc20d38bbf94837fc.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/favicon-128x128-e97066b91cc21b104c63bc7530ff819f.png
https://d3g6anj9jkury9.cloudfront.net/assets/favicons/favicon-196x196-b8cab44cf725c4fa0aafdbd237cdc4ed.png
link[rel*=icon][href], link[rel*=ICON][href]
link[rel="shortcut icon"][href], link[rel="apple-touch-icon-precomposed"][href]
my %Interesting = ...;
my $results = $ua->get( shift )
    ->result
    ->dom
    ->find( '...' )
    ->grep( sub { exists $Interesting{ $_->attr('rel') } } )
    ->map( attr => 'href' )
    ->to_array
    ;