昨日の夜、むしょうに「磯山さやか」の画像をたくさん見たくなって、 Flickr からキーワードにマッチした写真を一括でダウンロードする Perl のスクリプトを作ってみた。
使い方はこんな感じ。
$ ./flickr_fetcher.pl --keyword 磯山さやか --dir sayaka --api_key yourflickrapikey
すると、sayaka というディレクトリが無かったら自動的に作ってくれて、 Flickr 内でマッチした 総写真枚数 が表示されます。
$ ./flickr_fetcher.pl --keyword 磯山さやか --dir sayaka --api_key yourflickrapikey search keyword : 磯山さやか total count : 760
760枚もあるんですね。そして、勝手にダウンロード開始。
try to fetch : 200 OK : http://farm4.static.flickr.com/3285/3112920048_531a88761b_b.jpg try to fetch : 200 OK : http://farm4.static.flickr.com/3213/3084174182_463f9bd410_b.jpg try to fetch : 200 OK : http://farm4.static.flickr.com/3187/3067816386_f242e15580_o.jpg try to fetch : 200 OK : http://farm4.static.flickr.com/3280/3042192731_3ca24c0a5b_o.jpg try to fetch : 200 OK : http://farm4.static.flickr.com/3009/3042961088_cc993ba07d_b.jpg
Flickr の写真っていろいろサイズがあるけど、一番大きなサイズのものをダウンロードしています。 しばらく待つとダウンロードが終わって、sayaka ディレクトリには760枚の画像が。 これはいい。今いろんなグラビアアイドルの写真を取って来まくっています。 ちなみに、コマンドの引数に Flickr の api_key を渡さなくてはいけませんが、 環境変数に「FLICKR_API_KEY」が設定されていれば指定しなくて OK です。
もちろんエロっちいーこと以外にも使えます。 ダウンロードする写真のライセンスを指定できるので、例えば、CC の by アトリビュートの写真が欲しかったら以下のように license パラメータに 4 をセットします。
$ ./flickr_fetcher.pl --keyword sky --dir sky --license 4 --api_key yourflickrapikey
ある程度自由に使いたい写真を見つけたい時に便利かもね。
実装に関して、 クラス作るのに Moose 、Flickr API を叩くところで WebService::Simple を利用しています。 WebService::Simple は coderepos の最新版もしくは、先ほどアップしたCPANの 0.13 というヴァージョンのものを使います(ここに登場予定)。
この flickr_fetcher.pl、CodeRepos にアップしてあるけど とりあえず現状のスクリプトを以下、全コード張りつけ。 Flickr の写真で一番大きいやつの URL を取得するのに、 一度それぞれの写真に対して「flickr.photos.search」というメソッドを呼んでいるのがポイントかな。 おかしなところあったらツッコミください。
#!/usr/bin/perl
package FlickrFetcher;
use Moose;
use Moose::Util::TypeConstraints;
use Params::Coerce ();
use Digest::MD5 qw(md5_hex);
use Encode;
use LWP::UserAgent;
use Path::Class;
use POSIX qw(ceil);
use WebService::Simple;
use WebService::Simple::Parser::XML::Simple;
use XML::Simple;
use Perl6::Say;
our $VERSION = '0.01';
with 'MooseX::Getopt';
subtype 'Dir' => as 'Object' => where { $_->isa('Path::Class::Dir') };
coerce 'Dir' => from 'Str' => via { Path::Class::Dir->new($_) };
MooseX::Getopt::OptionTypeMap->add_option_type_to_map( 'Dir' => '=s' );
has 'keyword' => ( is => 'rw', isa => 'Str', required => 1 );
has 'dir' => ( is => 'rw', isa => 'Dir', required => 1, coerce => 1 );
has 'api_key' => ( is => 'rw', isa => 'Str' );
has 'license' => ( is => 'rw', isa => 'Int' );
has '_perpage' => ( is => 'ro', isa => 'Int', default => 500 );
has '_flickr' => ( is => 'rw', isa => 'WebService::Simple' );
has '_ua' => (
is => 'ro',
isa => 'LWP::UserAgent',
default => sub { LWP::UserAgent->new( keep_alive => 1 ) }
);
sub BUILD {
my ( $self, $args ) = @_;
unless ( $self->api_key ) {
if ( my $api_key = $ENV{FLICKR_API_KEY} ) {
$self->api_key($api_key);
}
else {
die "api_key is required\n";
}
}
my $xs = XML::Simple->new( KeepRoot => 1, keyattr => [] );
my $parser = WebService::Simple::Parser::XML::Simple->new( xs => $xs );
my $flickr = WebService::Simple->new(
base_url => "http://api.flickr.com/services/rest/",
param => { api_key => $self->api_key },
response_parser => $parser,
);
$self->_flickr($flickr);
}
__PACKAGE__->meta->make_immutable;
no Moose;
sub run {
my $self = shift;
mkdir $self->dir->relative if !-d $self->dir->is_absolute;
say "search keyword : " . $self->keyword;
my $photo_total = $self->photo_total( $self->keyword );
say "total count : " . $photo_total;
my $pages = ceil( $photo_total / $self->_perpage );
for my $current_page ( 1 .. $pages ) {
say "search page : $current_page";
$self->search( $self->keyword, $current_page, $self->_perpage );
}
}
sub search {
my ( $self, $keyword, $page , $perpage) = @_;
my $response = $self->_flickr->get(
{
method => "flickr.photos.search",
text => $keyword,
per_page => $perpage,
sort => 'date-posted-desc',
extras => 'date_upload',
page => $page,
license => $self->license || "",
}
);
my $xml = $response->parse_response;
$self->fetch($xml->{rsp}->{photos}->{photo});
}
sub fetch {
my ( $self, $photo_ref ) = @_;
for my $photo ( @$photo_ref ){
my $url = $self->photo_url( $photo->{id} );
my $file = $self->dir->file( md5_hex($url) . ".jpg" );
my $res = $self->_ua->mirror( $url, $file );
say "try to fetch : " . $res->status_line . " : $url";
}
}
sub photo_url {
my ( $self, $photo_id ) = @_;
my $response = $self->_flickr->get(
{
method => "flickr.photos.getSizes",
photo_id => $photo_id
}
);
my $xml = $response->parse_response;
my $largest_ref = pop @{ $xml->{rsp}->{sizes}->{size} };
return $largest_ref->{source};
}
sub photo_total {
my ( $self, $keyword ) = @_;
my $response = $self->_flickr->get(
{
method => "flickr.photos.search",
text => $keyword,
per_page => 1,
license => $self->license || "",
}
);
my $xml = $response->parse_response;
return $xml->{rsp}->{photos}->{total};
}
package main;
my $fetcher = FlickrFetcher->new_with_options();
$fetcher->run();
__END__
=head1 NAME
flickr_fetcher.pl - Fetch Flickr photos by keyword
=head1 SYNOPSIS
./flickr_fetcher.pl --keyword hoge --dir hoge --api_key yourflickrapikey
=head1 AUTHOR
Yusuke Wada E<lt>yusuke (at) kamawada.comE<gt>
=head1 LICENSE
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
Enjoy!
参考文献
- ラリー ウォール ジョン オーワント トム クリスチャンセン
- 単行本 / オライリー・ジャパン
- Amazon 売り上げランキング: 98834
- Amazon おすすめ度の平均:

-
いまだに10行以上のプログラムが書けません。 -
値段は高いけど・・・ -
CGIを自在にこなす第一歩の書 -
Perl文法の仕組みを詳細に知りたい人の本 -
ラクダが踊る
-
- 飯塚 昌太
- 大型本 / ワニブックス
- Amazon 売り上げランキング: 2500
- Amazon おすすめ度の平均:

-
好きだけどなぁ…。 -
表紙だけを見よう -
う?ん、どうでしょ -
お帰り! -
可愛い!! けど・・・
-
