Web::Queryの使い方練習のためにApple Storeのnew製品を取得する

この種のライブラリとして Web::Scraper があるが、Web::Scraper の DSL をおもいだすまでにどうしても時間がかかりがちだったので、こういう風なのもいいかなとおもった。jQuery は日常的につかってるので、わすれないし。

わーぃ。いつもWeb::Scraper使う時は昔書いたスクリプトを見直して書き方を思い出していたのでjQueryっぽい書き方ができると楽でいいです。
使い方忘れてもjQueryっぽいから思い出すのも早そうだし。



さっそく使い方を練習するために確認確認。
「何やろうかなぁ。ログインするようなページに対して使ってみようかなぁ」
とか色々考えてみたんですけど、とりあえず今は欲しいものがなかったので、新しいMacBook Proが出た時に、
「あ、出たんだ」
って思えるようなスクリプトを書くことにしました。


まずはページを確認。

http://store.apple.com/jp
Apple TVのところを見てみると「NEW」っていう画像が付いているので、きっと新製品にはこれが付くんだろうなと予測。



imgタグを確認してみるとclass="new-icon"が付いてるみたい。
これを元に製品名を取得してみる。


jQueryで取得

とりあえずjQueryでいつも通り書いてみる。
製品一覧は<div id="aos_family">内に全部詰まってるようなので、
そのdivの中にあるimg.new-iconを取得し、
さらにそれと同階層にあるテキストが欲しいので一旦上に上がってtextを取得。
ということでこんな感じ。

var product = jQuery('#aos_family img.new-icon')
  .parent()
    .text();

console.log(product);

Web::Queryを使って取得

Web::Queryを使って同じようにやってみようと思ったものの、
きっとjQueryのメソッドがそのまま実装されているはずはないと思うのでメソッドの確認。

[4:16]% perldoc -m Web::Query | ack '^sub ' 
sub wq { Web::Query->new(@_) }
sub __ua {
sub new {
sub new_from_url {
sub new_from_file {
sub new_from_html {
sub new_from_element {
sub end {
sub find {
sub html {
sub text {
sub attr {
sub each {
sub DESTROY {

多分、find,end,html,text,attr,eachを使って操作するみたい。
(これ見て気付いたのだけどuser_agent変更するインタフェースはないみたい)



parentがないので親に向かう操作はないとすると、さっきjQueryでやったやり方は捨てて違うアプローチで。
class="product"のliタグに製品一つずつが入っているので、その中にNEW画像があれば製品名を出力してみる。
ということでこんな感じにしました。

use strict;
use warnings;
use Web::Query;

wq('http://store.apple.com/jp')->find('#aos_family li.product')
    ->each(sub {
        $_[1]->each(sub {
            my(undef, $wq) = @_;
            return unless $wq->find('img.new-icon')->attr('class');

            warn $wq->text();
        })
    });

imgタグがあるかないかの確認はattr('class')で値返すかどうかで判断してます。



実際に実行実行。

[4:32]% perl sample.pl
   Apple TV ¥8,800   at sample.pl line 15.

でたーでたー。やりました。これはいじりやすいなぁ。