Net::Amazonでページング
Net::Amazonでページングがうまくいかなかったので、それに対応した方法を書く。
Amazon APIのページの概念は、1ページ10アイテム。ページ指定が1なら検索結果の1件目から10件目、2なら11件目から20件目のデータが取得される。
で、Net::Amazonだとどうなってるか。
ページ関連のパラメータは2つある。max_pagesと、page。
max_pagesは、1回の検索で取得するデータ量を指定する。デフォルト値は5。1回の検索で5ページ分=50アイテム分のデータを取得する。
変更するには、Catalystでモデルを作ってる場合だと /lib/MyApp/Model/Net/Amazon.pm をいじる。
__PACKAGE__->config( token => 'XXXXXXXXXXXXXXXXXXXX', secret_key => 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', locale => 'jp', max_pages => 3, );
上記のようにmax_pagesを追記してやる。ここでは3を指定しているので、3ページ分のデータが取得されるはず。
実際、次のように検索すると、30件のデータが取得される。
my $ua = $c->model('Net::Amazon'); my $response = $ua->search( keyword => 'perl', mode => 'books', );
もうひとつのpageは、検索の際、データ取得の始点を指定する。こんな感じ。
my $ua = $c->model('Net::Amazon'); my $response = $ua->search( keyword => 'perl', mode => 'books', page => 2, );
この結果、11件目から30件目までのデータが取得される。Amazon APIにとっての2ページ目(11件目〜20件目)から、max_pagesで指定したところまでのデータが取得されている模様。
実際のページングの動作を考えると、max_pagesで指定したデータ件数を1ページとみなして、2ページ目で31〜60件目、3ページで61〜90件目のデータを取得するように変更したい。
ソースを見ると、Net::Amazonのrequestの中、213行目からが、ページングの処理になっている。
# Stop if we've fetched max_pages already if(defined $page && $self->{max_pages} <= $page) { DEBUG("Fetched max_pages ($self->{max_pages}) -- stopping"); last; } if($res->is_page_available($ref, $new_items, $page)) { $page++; redo REQUEST; }
1回のリクエストで取ってこれるデータ量は10件に決まってるので、現在のページ数がmax_pages未満ならページ数を増やして再度リクエストするロジックになっている。
これだと、pageでどんな値を指定しようが、max_pagesで指定したページまでのデータしか取ってきてくれない。指定したpageがmax_pages以上であれば、1ページ分のデータになる。
では変更。
まず、request()メソッド開始直後の、変数の指定部分。
2行目をコメントアウトして3行目、5行目を追記。
my $url = URI->new($self->intl_url($request->amzn_xml_url())); # my $page = $request->page(); my $page = ( $request->page() - 1 ) * $self->{max_pages} + 1; my $ref; my $max_pages_in_this_search = $self->{max_pages} + $page - 1;
続いて、先ほど参照したページングのロジック部分。
2〜5行目をコメントアウトして、続きの4行を追記。
# Stop if we've fetched max_pages already # if(defined $page && $self->{max_pages} <= $page) { # DEBUG("Fetched max_pages ($self->{max_pages}) -- stopping"); # last; # } if(defined $page && $max_pages_in_this_search <= $page) { DEBUG("Fetched max_pages ($max_pages_in_this_search) -- stopping"); last; } if($res->is_page_available($ref, $new_items, $page)) { $page++; redo REQUEST; }
解説。
$pageの指定を変更して、max_pagesで指定した分を1pageとして、Amazon APIの開始ページを算出している。以下例。
- max_pages = 3
- page = 2
- $page = (2-1)*3-1 = 4
max_pages=3の場合の2ページ目は、Amazon APIでいう4ページ目となる。
$max_pages_in_this_searchの指定も追加している。この変数には、page指定を考慮して、Amazon APIで何ページ目まで検索するかを指定している。同じく例。
- max_pages = 3
- $page = 4
- $max_pages_in_this_search = 3+4-1 = 6
ここで使ってる$pageは、先ほど算出したほうの値。で、$max_pages_in_this_searchは6となる。
ロジック部分では、max_pagesではなく、$max_pages_in_this_searchを判定に使っている。
ということで、max_pages=3、page=2を指定した場合、Amazon APIでの4〜6ページ目のデータを取得するようになった。