概要

  • 大きな画像を表示する
  • ASINから大きな画像のURIを求めて存在するかどうか確認する。
  • 「content-type」が「image/jpeg」なら存在する、「image/gif」なら存在しない。

動作サンプル

Bookmarklet

javascript:
location = 'https://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=' + (location.href.match(/\/(dp|ASIN|product)\/(\w+)/))[2];

スクリプト

  • getImages.cgi

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    use utf8;
    use feature qw(say);
    use Encode;
    use LWP::UserAgent;
    use URI::Amazon::APA;
    use XML::Simple;
    use YAML::Syck qw(LoadFile DumpFile Dump);
    use CGI;
    use URI::Escape;
    use Template;
    use FindBin::libs;
    use TakeAmazon;
    use Term::Encoding qw(term_encoding);
    use open ':std' => ( $^O eq 'MSWin32' ? ':locale' : ':utf8' );
    
    $YAML::Syck::ImplicitUnicode = 1;
    $CGI::POST_MAX               = 1024;
    $|                           = 1;
    
    my $conf = loadConfig();
    
    #say Dump($conf);
    my $tt = Template->new(
        {   INCLUDE_PATH => "${FindBin::RealBin}/templates",
            ENCODING     => 'utf-8',
        }
    ) or die( Template->error() );
    
    my $q = new CGI;
    $q->charset('utf-8');
    my $cgiPath = $q->url( -absolute => 1 );
    my $args    = checkArgs(
        $conf,
        scalar $q->param('URI'),
        scalar $q->param('ASIN'),
        scalar $q->param('SHOT'),
        scalar $q->param('PAGE'),
        scalar $q->param('MOD'),
    );
    
    my $out = $q->header(
        -type    => 'text/html',
        -charset => 'utf-8',
    );
    
    #my $r = requestAws(
    #    $conf,
    #    {   Operation     => 'ItemSearch',
    #        SearchIndex   => 'All',
    #        ResponseGroup => 'ItemAttributes,Images',
    #        ItemId        => $args->{'ASIN'},
    #    },
    #);
    #say Dump($r);
    
    my $detail = getDetail( $conf, $args->{'URI'} );
    
    $tt->process(
        "form.html",
        {   urlCgiTop => $cgiPath,
            args      => $args,
            detail    => $detail,
            shots     => makeShots( $conf->{'VariableShots'} ),
            pages     => makePages( $conf->{'PageLabels'} ),
            images    => searchImages( $conf, $args ),
        },
        \$out
    ) or die( $tt->error );
    print $out;
  • conf/config.yml

    CgiName: Amazon getImages-JP
    ImageUriBase: https://images-na.ssl-images-amazon.com/images/P/{ASIN}.09.{SHOT}._SC{SIZE}ZZZZZZ_.jpg
    NoImageUri: https://images-na.ssl-images-amazon.com/images/G/09/nav2/dp/no-image-no-ciu.gif
    DetailUri: https://www.amazon.co.jp/dp/{ASIN}/
    CustomerImageUri: https://www.amazon.co.jp/gp/customer-media/product-gallery/{ASIN}
    FixShots:
      - Name: Main
        Key: MAIN
      - Name: Top
        Key: TOPP
      - Name: Bottom
        Key: BOTT
      - Name: Left
        Key: LEFT
      - Name: Right
        Key: RGHT
      - Name: Front
        Key: FRNT
      - Name: Back
        Key: BACK
    VariableShots:
      - Name: "PIECE SHOTS / 書籍以外のその他の画像"
        Key: PT
      - Name: "INTERIOR SHOTS / 書籍のその他の画像"
        Key: IN
    Sizes:
      - Name: Large
        Key: RM
      - Name: Medium
        Key: L
      #- Name: Small
      #  Key: M
    PageStep: 10
    AWS:
      SERVICE_URI: https://webservices.amazon.co.jp/onca/xml
      AWS_ACCESS_KEY_ID: <your access key>
      SECRET_ACCESS_KEY: <your secret key>
      ASSOCIATE_TAG: <your associate tag>
  • lib/TakeAmazon.pm

    # TakeAmazon.pm
    # Amazon サポートモジュール
    
    package TakeAmazon;
    
    use strict;
    use warnings;
    use utf8;
    use feature qw(say);
    use Encode;
    use Exporter 'import';
    use YAML::Syck qw(LoadFile DumpFile Dump);
    use Path::Class;
    use LWP::UserAgent;
    use URI::Amazon::APA;
    use XML::Simple;
    use Lingua::JA::Regular::Unicode;
    use lib qw( /home/Shared/lib C:/_Take/lib );
    use Term::Encoding qw(term_encoding);
    use open ':std' => ( $^O eq 'MSWin32' ? ':locale' : ':utf8' );
    
    $YAML::Syck::ImplicitUnicode   = 1;
    $XML::Simple::PREFERRED_PARSER = 'XML::Parser';
    
    our @EXPORT = qw(
        loadConfig startsWith
        makePageLabels checkArgs makeShots makePages getDetail
        makeAwsUri requestAws
        searchImages searchForShots searchForSizes
    );
    
    my $ua = LWP::UserAgent->new( keep_alive => 6 );
    
    sub loadConfig {
        my $file = file(__FILE__)->absolute->dir . '/../conf/config.yml';
        my $conf = LoadFile($file) or die("${file}: $!");
        $conf->{'PageLabels'} = makePageLabels( $conf->{'PageStep'} );
        return $conf;
    }
    
    sub startsWith {
        my $text   = shift or return;
        my $prefix = shift or return;
        return $prefix eq substr( $text, 0, length($prefix) );
    }
    
    sub makePageLabels {
        my $step       = shift || 20;
        my @pageLabels = map {
                  'PT'
                . substr( '0' . ( $_ * $step + 1 ),     -2 ) . '-PT'
                . substr( '0' . ( ( $_ + 1 ) * $step ), -2 )
        } ( 0 .. ( 99 / $step ) );
        $pageLabels[0] = 'Main, ' . $pageLabels[0];
        $pageLabels[$#pageLabels] =~ s/\d+$/99/;
        return [@pageLabels];
    }
    
    sub checkArgs {
        my $conf     = shift or return;
        my $uri      = shift || '';
        my $asin     = shift || '';
        my $shotType = shift || 0;
        my $page     = shift || 0;
        my $mod      = !!shift;
        if ( !$asin ) {
            $uri =~ /\/(dp|ASIN|product)\/(?<asin>[\w]+)/;
            $asin = $+{asin};
        }
        if ($asin) {
            $uri = $conf->{'DetailUri'};
            $uri =~ s/\{ASIN\}/$asin/;
        }
        if ( $shotType < 0 || $#{ $conf->{'VariableShots'} } < $shotType ) {
            $shotType = 0;
        }
        if ( $page < 0 || $#{ $conf->{'PageLabels'} } < $page ) {
            $page = 0;
        }
        return {
            URI      => $uri,
            ASIN     => $asin,
            ShotType => $shotType,
            Page     => $page,
            Mod      => $mod,
        };
    }
    
    sub makeShots {
        my $variableShots = shift or return;
        my $index         = 0;
        return [ map { { value => $index++, label => $_->{'Name'}, }; } @{$variableShots} ];
    }
    
    sub makePages {
        my $pageLabels = shift or return;
        my $index      = 0;
        return [ map { { value => $index++, label => $_, }; } @{$pageLabels} ];
    }
    
    sub getDetail {
        my $conf = shift or return;
        my $uri  = shift or return;
        my $r    = $ua->get($uri);
        my $html = $r->decoded_content;
        $html =~ /<meta\scontent="(?<content>[^"]+)"\s+name="description"\s*\/>/;
        my $title = $+{'content'};
        $title =~ s/^Amazon\.\S+\s*//i;
        $title = katakana_h2z($title);
        return {
            Title => $title || 'No Title',
            URI   => $uri . '?tag=' . $conf->{'AWS'}{'ASSOCIATE_TAG'},
        };
    }
    
    sub makeAwsUri {
        my $conf = shift or return;
        my $opt  = shift or return;
        my $aws  = $conf->{'AWS'};
        my $u    = URI::Amazon::APA->new( $aws->{'SERVICE_URI'} );
        $u->query_form(
            Service      => 'AWSECommerceService',
            AssociateTag => $aws->{'ASSOCIATE_TAG'},
            %{$opt},
        );
        $u->sign(
            key    => $aws->{'AWS_ACCESS_KEY_ID'},
            secret => $aws->{'SECRET_ACCESS_KEY'},
        );
        return $u;
    }
    
    sub requestAws {
        my $conf = shift or return;
        my $opt  = shift or return;
        my $r = $ua->get( makeAwsUri( $conf, $opt ) );
        return {
            IsSuccess => $r->is_success,
            Status    => $r->status_line,
            Content   => XMLin(
                $r->decoded_content,
                ForceArray =>
                    [ 'Item', 'Error', 'DetailPageURL', 'SalesRank', 'ProductGroup', 'Title', ],
                KeyAttr => { 'Item' => '+ASIN', },
            ),
        };
    }
    
    sub searchImages {
        my $conf = shift or return;
        my $args = shift or return;
        if ( !$args->{'ASIN'} ) {
            return;
        }
        my @images  = ();
        my $uriBase = $conf->{'ImageUriBase'};
        $uriBase =~ s/\{ASIN\}/$args->{'ASIN'}/e;
        if ( $args->{'Page'} == 0 ) {
            push( @images, searchForShots( $conf, $uriBase, $conf->{'FixShots'} ) );
        }
        my @shots = map {
            my $shot
                = $conf->{'VariableShots'}[ $args->{'ShotType'} ]{'Key'}
                . substr( '0' . ( $args->{'Page'} * $conf->{'PageStep'} + $_ ), -2 );
            { Name => $shot, Key => $shot, };
        } ( 1 .. $conf->{'PageStep'} );
        push( @images, searchForShots( $conf, $uriBase, \@shots ) );
        return [@images];
    }
    
    sub searchForShots {
        my $conf    = shift or return;
        my $uriBase = shift or return;
        my $shots   = shift or return;
        my @images  = ();
        foreach my $shot ( @{$shots} ) {
            my $uri = $uriBase;
            $uri =~ s/\{SHOT\}/$shot->{'Key'}/e;
            if ( my $image = searchForSizes( $conf, $uri, $shot->{'Name'} ) ) {
                push( @images, $image );
            }
        }
        return @images;
    }
    
    sub searchForSizes {
        my $conf    = shift or return;
        my $uriBase = shift or return;
        my $shot    = shift or return;
        foreach my $size ( @{ $conf->{'Sizes'} } ) {
            my $uri = $uriBase;
            $uri =~ s/\{SIZE\}/$size->{'Key'}/e;
            my $r = $ua->get($uri);
            if ( $r->is_success && $r->header('content-type') eq 'image/jpeg' ) {
                return { Title => $shot . '_' . $size->{'Name'}, Uri => $uri, };
            }
        }
        return;
    }
    
    1;
  • templates/form.html

    <!DOCTYPE html>
    <html lang="ja">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <link rel="stylesheet" type="text/css" href="/take.css" />
      <link rel="stylesheet" type="text/css" href="/Amazon.css" />
      <title>Amazon getImages-JP</title>
    </head>
    
    <body>
      <h1><a name="top" href="[% urlCgiTop %]">Amazon getImages-JP</a></h1>
      <div>
        <form method="POST" action="[% urlCgiTop %]" enctype="application/x-www-form-urlencoded">
          <table>
            <tbody>
              [% IF detail %]
              <tr>
                <th>TITLE</th>
                <td><a href="[% detail.URI %]" target="_blank">[% detail.Title %]</a></td>
              </tr>
              [% END %]
              <tr>
                <th>ASIN</th>
                <td><input name="ASIN" type="text" value="[% args.ASIN %]"></td>
              </tr>
              <tr>
                <th>URI</th>
                <td><input name="URI" type="text" size="50" value="[% args.URI %]"></td>
              </tr>
              <tr>
                <th>SHOT</th>
                <td>
                  <select name="SHOT">
                    [% FOREACH shot IN shots %]
                    <option value="[% shot.value %]" [% IF shot.value==args.ShotType %] selected [% END %]>[% shot.label %]
                    </option>
                    [% END %]
                  </select>
                </td>
              </tr>
              <tr>
                <th>PAGE</th>
                <td>
                  <select name="PAGE">
                    [% FOREACH page IN pages %]
                    <option value="[% page.value %]" [% IF page.value==args.Page %] selected [% END %]>[% page.label %]
                    </option>
                    [% END %]
                  </select>
                </td>
              </tr>
              <tr>
                <td colspan="2">
                  <input name=".submit" type="submit">
                  <input name=".reset" type="reset">
                </td>
              </tr>
            </tbody>
          </table>
        </form>
      </div>
      [% IF images %]
      <div>
        [% FOREACH image IN images %]
        <h2><a href="#top" name="[% image.Title %]">[% image.Title %]</a></h2>
        <img alt="[% image.Title %]" title="[% image.Title %]" src="[% image.Uri %]">
        [% END %]
      </div>
      <div class="panelIndex">
        <ol class="default">
          [% FOREACH image IN images %]
          <li><a href="#[% image.Title %]">[% image.Title %]</a></li>
          [% END %]
        </ol>
        <p><a href="#top">Top</a></p>
      </div>
      [% END %]
    </body>
    
    </html>
  • Amazon.css

    /* Amazon.css */
    
    .default {
      text-align: initial;
    }
    
    .panelIndex {
      position: fixed;
      top: 0em;
      right: 0em;
      padding: 0em 0.5em 0em 0em;
      text-align: right;
      background-color: #d0d0f0;
      border: solid;
      border-width: thin;
    }

リンク