HTML::FeaturedImage - URLに含まれる画像のうち、重要そうなものを取り出すためのPerlモジュール
yuisekiが「エントリのメイン画像抽出があるといいかも」と言ってたときに、昼飯まで暇だったので作った。結果のサンプルはこちら。
仕組みはてきとう。まずURLをたくさん与え、その先にある画像の数を数える。たくさんのページにでてきたり、何度もおなじページに出てくる画像はどうでもいいものとして、消す。よくあるやり方だけど強力。
よく考えるとHTML::じゃない感じがしてきた。あとで直すかも。HTML::としてふさわしくするため、Web::Scraperにcontent渡せるようにした。
$content = "<html>..."; $hfi->add_page($url, $content);
あと、リンク先が画像っぽいURLのときにはa hrefも取るようにした。閾値のキャッシュとかちょっとアルゴリズム変更とか、細かいところも変更。ちょっとノイズ入るようになったけど、たぶん欲しい物は確実に全部取れるチューニングになってると思う。閾値の式とか画像っぽいURL判定は設定とかプラグインに出したほうがいいかもな。
サンプルを生成するipic.pl
#!/usr/bin/perl use strict; use warnings; use URI; use XML::Feed; use Template; use HTML::FeaturedImage; my $home = shift or die 'usage : ./ipic.pl http://www.akibablog.net/'; my @feeds = XML::Feed->find_feeds($home); die 'no feed' unless (@feeds); my $feed = XML::Feed->parse(URI->new($feeds[0])); my $template = <<"TEMPLATE"; <html> <head><title>demo: HTML::FeaturedImage</title></head> <body> [% FOR url IN hfi.urls %] <div> <h3>[% url %]</h3> <h4>original</h4> <p>[% FOR imageurl IN hfi.original(url) %]<a href="[% imageurl %]"><img src="[% imageurl %]" width="80"></a>[% END %]</p> <h4>predicted</h4> <p>[% FOR imageurl IN hfi.predict(url) %]<a href="[% imageurl %]"><img src="[% imageurl %]" width="80"></a>[% END %]</p> </div> [% END %]</body> </html> TEMPLATE my $hfi = HTML::FeaturedImage->new; for my $entry ($feed->entries) { my $url = $entry->link; $hfi->add_page($url); } my $tt = Template->new; $tt->process(\$template, {hfi => $hfi});
HTML/FeaturedImage.pm
package HTML::FeaturedImage; use strict; use warnings; use URI; use Web::Scraper; use List::MoreUtils qw(:all); use Statistics::Lite qw(:all); sub new { my $pkg = shift; bless {}, $pkg; } sub urls { my $self = shift; return @{$self->{urls}}; } sub add_page { my ($self, $url, $content) = @_; push @{$self->{urls}}, $url; my $uri = URI->new($url); my $scraper = scraper { process "img", 'imgs[]' => '@src'; process "a", 'anchors[]' => '@href'; }; my @args = ($uri); unshift @args, \$content if (defined $content); my $r = $scraper->scrape(@args); my @imgs; push @imgs, @{$r->{imgs}}; push @imgs, grep /\.(jpe?g|gif|png|bmp)$/i, @{$r->{anchors}}; map {$self->{db}->{all}->{$_}++} uniq @imgs; map {$self->{db}->{$url}->{$_}++} uniq @imgs; delete $self->{threshold} if (defined $self->{threshold}); return $self; } sub threshold { my $self = shift; return $self->{threshold} if (defined $self->{threshold}); my @dba = values %{$self->{db}->{all}}; $self->{threshold} = mean(@dba) + stddevp(@dba)/2; } sub predict { my ($self, $url) = @_; my @informative_imgs; my $img_db = $self->{db}; my $all = $img_db->{all}; my $imgs = $img_db->{$url}; while (my ($img, $num) = each %$imgs) { if ($self->threshold >= $all->{$img}) { push @informative_imgs, $img; } } return @informative_imgs; } sub original { my ($self, $url) = @_; return keys %{$self->{db}->{$url}}; } 1;