ishiducaの日記 このページをアンテナに追加 RSSフィード

2011-05-20

[]WWW::Pixiv::Downloadを使ったサンプル その1 22:50 WWW::Pixiv::Downloadを使ったサンプル その1 - ishiducaの日記 を含むブックマーク はてなブックマーク - WWW::Pixiv::Downloadを使ったサンプル その1 - ishiducaの日記 WWW::Pixiv::Downloadを使ったサンプル その1 - ishiducaの日記 のブックマークコメント

WWW::Pixiv::Download的な物 その2」の方を使います。

コマンドラインから illust_id のコンテンツを保存するスクリプト

$ perl pixiv_dl.pl 0123456789

ってやると $HOME/Pictures/Pixiv ディレクトリ以下に「author/title/」のディレクトリを作って、その中にコンテンツを保存します

--> success: login. "http://www.pixiv.net/mypage.php" now.
--> access: "http://www.pixiv.net/member_illust.php?mode=medium&illust_id=0123456789"
--> not found directory "/Users/YOU/Pictures/Pixiv/some_author/some_title".
--> create new directory "/Users/YOU/Pictures/Pixiv/some_author/some_title".
--> success: download. "/Users/YOU/Pictures/Pixiv/some_author/some_title/0123456789_m.jpg"
--> access: "http://www.pixiv.net/member_illust.php?mode=manga&illust_id=0123456789"
--> success: download. "/Users/YOU/Pictures/Pixiv/some_author/some_title/0123456789_p0.jpg"
--> success: download. "/Users/YOU/Pictures/Pixiv/some_author/some_title/0123456789_p1.jpg"
--> success: download. "/Users/YOU/Pictures/Pixiv/some_author/some_title/0123456789_p2.jpg"
--> success: download. "/Users/YOU/Pictures/Pixiv/some_author/some_title/0123456789_p3.jpg"
--> success: download. "/Users/YOU/Pictures/Pixiv/some_author/some_title/0123456789_p4.jpg"
--> success: download. "/Users/YOU/Pictures/Pixiv/some_author/some_title/0123456789_p5.jpg"
--> success: download. "/Users/YOU/Pictures/Pixiv/some_author/some_title/0123456789_p6.jpg"
--> success: download. "/Users/YOU/Pictures/Pixiv/some_author/some_title/0123456789_p7.jpg"
--> success: download. "/Users/YOU/Pictures/Pixiv/some_author/some_title/0123456789_p8.jpg"
--> success: download. "/Users/YOU/Pictures/Pixiv/some_author/some_title/0123456789_p9.jpg"

という感じでダウンロード状況を提示してくれる

pixiv_dl.pl

#!/usr/bin/env perl -s
use strict;
use warnings;
use Path::Class;
use Config::Pit;
use WWW::Pixiv::Download;

our($h);
my $usage = "usage: $0 illust_id\n";

$h and $usage and exit 0;
@ARGV or die $usage;

my $config = pit_get('www.pixiv.net', require => {
    pixiv_id => 'my pixiv_id',
    pass     => 'my pass',
});
die 'pit_get failed' if ! %$config;


my $client = WWW::Pixiv::Download->new(
    pixiv_id => $config->{pixiv_id},
    pass     => $config->{pass},
    look     => 1, # このオプションを付けるとDLの進捗状況を示してくれる
);

my $illust_id   = $ARGV[0];

# メタデータ(作者名とか作品タイトルとか)を取得
my $scraped_response = $client->prepare_download($illust_id);

$scraped_response->{author_name} =~ s/\//_/g;
$scraped_response->{title}       =~ s/\//_/g;
my $dir = join '/',
    "$ENV{HOME}/Pictures/Pixiv",
    $scraped_response->{author_name},
    $scraped_response->{title};

# ディレクトリを作る
unless (-e $dir) {
    warn qq(--> not found directory "${dir}".\n);
    dir($dir)->mkpath or die $!;
    warn qq(--> create new directory "${dir}".\n);
    $dir = "${dir}/";
}

$client->download($illust_id, {
    mode      => 'medium',
    path_name => $dir,
});

$client->download($illust_id, {
    path_name => $dir,
});

exit 0;

[]WWW::Pixiv::Download的な物 その2 20:50 WWW::Pixiv::Download的な物 その2 - ishiducaの日記 を含むブックマーク はてなブックマーク - WWW::Pixiv::Download的な物 その2 - ishiducaの日記 WWW::Pixiv::Download的な物 その2 - ishiducaの日記 のブックマークコメント

【補足】最新のバージョンは ishiduca/p5-www-pixiv-download - GitHub にあります。こちらは、ユーザーエージェントを WWW::Mechanize から LWP::UserAgent に変更しています(2011.05.22)

WWW::Pixiv::Download的なもの」のLWP::UserAgent版...にするついでにメソッドもいじった。

コードを書くときは WWW::Mechanize の方が楽ということを実感もした。

メソッド

  • new
my $client = WWW::Pixiv::Download->new(
    pixiv_id => 'your pixiv id',
    pass     => 'your pass',
    look     => 1, # ページ変遷を表示したいときのオプション
);
  • download
# illust_idのオジリナルサイズのファイルをダウンロードします
# マンガ形式の場合は、漫画ページで表示されるイラスト(複数枚)をダウンロードします
$client->download($illust_id);
  or
$client->download($illust_id, {
    mode      => 'medium',
    path_name => 'foo/bar/',
    file_name => $new_file_name, # 
});
  or
$client->download($illustid, {
    cb => \&callback,
});
# cbで指定するコールバックオプションは LWP::UserAgent の ":content_cb"
  • prepare_download

ダウンロードするイラスト(漫画)のタイトル、概要、作者名を含んだハッシュリファレンスを返します。(Web::Scraper、$scraper->scrape(...)の結果が入ってる )

my $contents_data = $client->prepare_download($illust_id);
my $illust_title       = $contents_data->{title};
my $illust_description = $contents_data->{description};
my $author_name        = $contents_data->{author_name};

todo

  • マンガ形式のコンテンツの処理をどうしたもんかと
  • ごちゃごちゃしてるコードをどうにかしたい

WWW/Pixiv/Download.pm

package WWW::Pixiv::Download;

use strict;
use Carp;
use URI;
use LWP::UserAgent;
use Web::Scraper;
use File::Basename;

our $VERSION = '0.0.2';

my $home   = 'http://www.pixiv.net';
my $login  = "${home}/login.php";
my $mypage = "${home}/mypage.php";

my $default_path_name = './';

sub new {
    my $class = shift;
    my %args  = @_;

    $args{is_logged_in} = '0';
    $args{Referer}      = '';
    $args{user_agent}   = LWP::UserAgent->new( cookie_jar => {} );

    push @{$args{user_agent}->requests_redirectable}, 'POST';

    bless \%args, $class;
}

sub download {
    my($self , $illust_id, $args) = @_;

    my $res_scrape = $self->{res_scrape};
    unless ($res_scrape->{img_src}        =~ m!$illust_id!
        and $res_scrape->{to_bigImg_href} =~ m!$illust_id!
        and $self->{Referer}              =~ m!$illust_id!) {
            $res_scrape = $self->prepare_download($illust_id);
    }

    if ($args->{mode} eq 'medium' or $args->{mode} eq 'm') {
        delete $self->{mode};
        $self->save_file($res_scrape->{img_src}, $args);
    } else {
        my $res = $self->{user_agent}->get("${home}/" . $res_scrape->{to_bigImg_href},
            'Referer' => $self->{Referer},
        );
        Carp::croak qq(! Download failed: ) . $res->status_line . "\n" if $res->is_error;
        $self->{Referer} = $res->base;
        warn '--> access: "' . $self->{Referer} . qq("\n) if $self->{look};

        if ($res->base =~ m!mode=big!) {
            my $scraper = scraper {
                process '//img[1]', 'img_src' => '@src';
            };
            my $res_scrape = $scraper->scrape($res->decoded_content);
            $self->save_file($res_scrape->{img_src}, $args);
        } else {
            my $content = $res->decoded_content;
            while ($content =~ m!unshift\('(http://([^\']+)?)'!g) {
                $self->save_file($1, $args);
            }
        }
    }

    $self;
}

sub prepare_download {
    my($self, $illust_id) = @_;

    Carp::croak qq(! failed: not found param "illust_id".) unless $illust_id;

    $self->login if $self->{is_logged_in} ne '1';

    my $uri = URI->new( "${home}/member_illust.php" );
    $uri->query_form(
        mode      => 'medium',
        illust_id => $illust_id,
    );

    my $res   = $self->{user_agent}->get( $uri );
    my %query = URI->new( $res->base )->query_form;

    if ($res->is_error) {
        Carp::croak '! failed: '. $res->status_line
            .': can not go to "'. $uri->as_string . qq("\n);
    } elsif ($query{mode} ne 'medium' or $query{illust_id} ne $illust_id) {
        Carp::croak '! failed: can not go to "'. $uri->as_string . '". now "'
             . $res->base . qq("\n);
    }

    $self->{Referer} = $res->base;

    warn '--> access: "'. $self->{Referer}. qq("\n) if $self->{look};

    my $scraper = scraper {
        process '//h3[1]', 'title' => 'TEXT';
        process '//p[@class="works_caption"]', 'description' => 'HTML';
        process '//a[@class="avatar_m"]', 'author_name' => '@title';
        process '//a[@class="avatar_m"]', 'author_url' => '@href';
        process '//div[@class="works_display"]/a[1]', 'to_bigImg_href' => '@href';
        process '//div[@class="works_display"]/a[1]/img[1]', 'img_src' => '@src';
    };

    $self->{res_scrape} = $scraper->scrape($res->decoded_content);
}

sub login {
    my $self = shift;
    my %args = @_;
    my $res;

    $self->{pixiv_id} = $args{pixiv_id} if $args{pixiv_id};
    $self->{pass}     = $args{pass}     if $args{pass};

    $self->{pixiv_id} or Carp::croak qq(! failed: not found "pixiv_id".\n);
    $self->{pass}     or Carp::croak qq(! failed: not found "pass".\n);

    $res = $self->{user_agent}->post($login, content => {
        'mode'     => 'login',
        'pixiv_id' => $self->{pixiv_id},
        'pass'     => $self->{pass},
    });

    if ($res->is_error) {
        $self->{is_logged_in} = '0';
        Carp::croak '! failed: login. ' . $res->status_line;
    } elsif ($res->base =~ m!index\.php!) {
        $self->{is_logged_in} = '0';
        Carp::croak qq(! failed: login. because of bad "pixiv_id" and "pass"\n);
    }
    $self->{Referer} = $res->base;
    $self->{is_logged_in} = '1';

    warn '--> success: login. "' . $self->{Referer} . '" now.'. "\n" if $self->{look};
    $self;
}

sub save_file {
    my($self, $img_src, $args) = @_;
    my $res;

    my $file_name = $args->{file_name} || basename $img_src;
    my $path_name = $args->{path_name} || $default_path_name;
    my $file_path = "${path_name}${file_name}";
    $file_path =~ s/\?.*//;
    unless (-e $file_path) {
        if (ref $args->{cb} eq 'CODE') {
          $res = $self->{user_agent}->get($img_src,
            'Referer'     => $self->{Referer},
            ':content_cb' => $args->{cb},
         );
      } else {
            $res = $self->{user_agent}->get($img_src,
                'Referer'       => $self->{Referer},
                ':content_file' => $file_path,
            );
      }
        Carp::croak '! Download failed: '. $res->status_line . "\n" if $res->is_error;
        warn '--> success: download. "' . $file_path . qq("\n) if $self->{look};
    } else {
        warn '--> skip: "'. $file_path . qq(" that already exists.\n) if $self->{look};
    }

}

1;

コマンドラインからダウンロードさせるスクリプトは明日アップします

GracelinGracelin2011/10/08 16:25Why does this have to be the ONLY reliable socure? Oh well, gj!

dctkfydctkfy2011/10/10 19:11kkQ9yQ , [url=http://ghqjxhukgnhw.com/]ghqjxhukgnhw[/url], [link=http://lstbpwczbflg.com/]lstbpwczbflg[/link], http://vnilkrgwluob.com/

riemxpriemxp2011/10/12 00:03jLmV3P <a href="http://sdavwdzlkusk.com/">sdavwdzlkusk</a>

qqmmqrgnssqqmmqrgnss2011/10/13 01:46x3v1n6 , [url=http://vkilptnlqxpd.com/]vkilptnlqxpd[/url], [link=http://qhisbkxjuzpg.com/]qhisbkxjuzpg[/link], http://cgqzyaxvzjwz.com/

bfnhpqpeubbfnhpqpeub2014/04/11 15:18bimtqqfsm, <a href="http://www.zbcxpykjkw.com/">elbrdiaper</a> , [url=http://www.lqbypjbpic.com/]axxhfzpxtr[/url], http://www.sgwymcxhuo.com/ elbrdiaper

トラックバック - http://perl.g.hatena.ne.jp/ishiduca/20110520