Table of Contents
概要
- 大きな画像を表示する
- 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; }