deba78a38b8dd44b8d8bd4435198f4ab4e5d1bea
Perl/Amazon/getImages.md
... | ... | @@ -6,329 +6,453 @@ |
6 | 6 | - 「content-type」が「image/jpeg」なら存在する、「image/gif」なら存在しない。 |
7 | 7 | |
8 | 8 | # 動作サンプル |
9 | -- [CGI Top](http://www.takeash.net/cgi-bin/Amazon/getImages.cgi) |
|
10 | - - &amazon(B001EQ6A80);<br /> |
|
11 | -[画像一覧](http://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B001EQ6A80) |
|
12 | - - &amazon(B002MZZ33K);<br /> |
|
13 | -[画像一覧](http://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B002MZZ33K) |
|
14 | - - &amazon(B0026RIRRS);<br /> |
|
15 | -[画像一覧](http://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B0026RIRRS) |
|
16 | - - &amazon(B002H9WBNQ);<br /> |
|
17 | -[画像一覧](http://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B002H9WBNQ) |
|
18 | - - &amazon(B002L16FZU);<br /> |
|
19 | -[画像一覧](http://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B002L16FZU) |
|
20 | - - &amazon(B0019JNTQS);<br /> |
|
21 | -[画像一覧](http://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B0019JNTQS) |
|
22 | - - &amazon(B002SW3N16);<br /> |
|
23 | -[画像一覧](http://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B002SW3N16) |
|
24 | - - &amazon(4775307614);<br /> |
|
25 | -[画像一覧](http://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=4775307614&SHOT=IN) |
|
9 | +- [CGI Top](https://www.takeash.net/cgi-bin/Amazon/getImages.cgi) |
|
10 | + - [figma 初音ミク](https://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B001EQ6A80) |
|
11 | + - [ねんどろいどぷち ボーカロイド シリーズ01 BOX](https://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B002MZZ33K) |
|
12 | + - [figma ファイアボール ドロッセル](https://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B0026RIRRS) |
|
13 | + - [ファイアボール ねんどろいど ドロッセル](https://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B002H9WBNQ) |
|
14 | + - [RVR-14 フェイ・イェン・ザ・ナイト DNA SIDE 1/100スケールプラスチックキット](https://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B002L16FZU) |
|
15 | + - [BAYONETTA 特典 スペシャルサウンドトラック「RODIN'S SELECTION」付き](https://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B0019JNTQS) |
|
16 | + - [BAYONETTA (特典無し)](https://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=B002SW3N16) |
|
17 | + - [大槍葦人画集 Chronicle LIMITED EDITION](https://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=4775307614&SHOT=1) |
|
18 | + - 数学文章作法 推敲編 [Page:0](https://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=4480095268) [Page:1](https://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=4480095268&PAGE=1) [Page:2](https://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=4480095268&PAGE=2) |
|
26 | 19 | |
27 | 20 | # Bookmarklet |
28 | 21 | ```javascript |
29 | -javascript:location='http://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN='+(location.href.match(/\/(dp|ASIN|product)\/([\w]+)/))[2]; |
|
22 | +javascript: |
|
23 | +location = 'https://www.takeash.net/cgi-bin/Amazon/getImages.cgi?ASIN=' + (location.href.match(/\/(dp|ASIN|product)\/(\w+)/))[2]; |
|
30 | 24 | ``` |
31 | 25 | |
32 | 26 | # スクリプト |
33 | -- [getImages.zip](getImages.zip) |
|
27 | +- getImages.cgi |
|
34 | 28 | ```perl |
35 | 29 | #!/usr/bin/perl |
36 | 30 | |
37 | 31 | use strict; |
38 | 32 | use warnings; |
39 | 33 | use utf8; |
34 | +use feature qw(say); |
|
40 | 35 | use Encode; |
41 | 36 | use LWP::UserAgent; |
42 | 37 | use URI::Amazon::APA; |
43 | 38 | use XML::Simple; |
44 | -use YAML::Syck; |
|
45 | -use CGI::Pretty qw( -no_xhtml *table *ol ); # //HTML 4.01 Transitional//EN |
|
39 | +use YAML::Syck qw(LoadFile DumpFile Dump); |
|
40 | +use CGI; |
|
46 | 41 | use URI::Escape; |
42 | +use Template; |
|
43 | +use FindBin::libs; |
|
44 | +use TakeAmazon; |
|
45 | +use Term::Encoding qw(term_encoding); |
|
46 | +use open ':std' => ( $^O eq 'MSWin32' ? ':locale' : ':utf8' ); |
|
47 | 47 | |
48 | 48 | $YAML::Syck::ImplicitUnicode = 1; |
49 | -$CGI::POST_MAX = 1024; |
|
50 | - |
|
51 | -binmode( STDIN, ":utf8" ); |
|
52 | -binmode( STDOUT, ":utf8" ); |
|
53 | -binmode( STDERR, ":utf8" ); |
|
54 | - |
|
55 | -# 自動フラッシュ有効化 (バッファリングを無効化) |
|
56 | -$| = 1; |
|
57 | - |
|
58 | -my $confyaml = './ID.yaml'; |
|
59 | -my $conf = YAML::Syck::LoadFile( $confyaml ) or die( "$confyaml: $!\n" ); |
|
60 | - |
|
61 | -my $cginame = 'Amazon getImages-JP'; |
|
62 | -my $ImageUriBase = |
|
63 | - 'http://images-jp.amazon.com/images/P/%ASIN%.09.%SHOT%._SC%SIZE%ZZZZZZ_.jpg'; |
|
64 | -my $NoImageUri = 'http://images-jp.amazon.com/images/G/09/nav2/dp/no-image-no-ciu.gif'; |
|
65 | -my $DetailUri = 'http://www.amazon.co.jp/dp/%ASIN%/'; |
|
66 | -my $CustomerImageUri = 'http://www.amazon.co.jp/gp/customer-media/product-gallery/%ASIN%'; |
|
67 | - |
|
68 | -my @ShotsFixList = ( |
|
69 | - { 'name' => 'Main', 'key' => 'MAIN', }, |
|
70 | - { 'name' => 'Top', 'key' => 'TOPP', }, |
|
71 | - { 'name' => 'Bottom', 'key' => 'BOTT', }, |
|
72 | - { 'name' => 'Left', 'key' => 'LEFT', }, |
|
73 | - { 'name' => 'Right', 'key' => 'RGHT', }, |
|
74 | - { 'name' => 'Front', 'key' => 'FRNT', }, |
|
75 | - { 'name' => 'Back', 'key' => 'BACK', }, |
|
49 | +$CGI::POST_MAX = 1024; |
|
50 | +$| = 1; |
|
51 | + |
|
52 | +my $conf = loadConfig(); |
|
53 | + |
|
54 | +#say Dump($conf); |
|
55 | +my $tt = Template->new( |
|
56 | + { INCLUDE_PATH => "${FindBin::RealBin}/templates", |
|
57 | + ENCODING => 'utf-8', |
|
58 | + } |
|
59 | +) or die( Template->error() ); |
|
60 | + |
|
61 | +my $q = new CGI; |
|
62 | +$q->charset('utf-8'); |
|
63 | +my $cgiPath = $q->url( -absolute => 1 ); |
|
64 | +my $args = checkArgs( |
|
65 | + $conf, |
|
66 | + scalar $q->param('URI'), |
|
67 | + scalar $q->param('ASIN'), |
|
68 | + scalar $q->param('SHOT'), |
|
69 | + scalar $q->param('PAGE'), |
|
70 | + scalar $q->param('MOD'), |
|
76 | 71 | ); |
77 | 72 | |
78 | -my @ShotsVarList = qw( PT IN ); |
|
79 | -my %ShotsTypeList = ( |
|
80 | - 0 => 'PIECE SHOTS / 書籍以外のその他の画像', |
|
81 | - 1 => 'INTERIOR SHOTS / 書籍のその他の画像', |
|
73 | +my $out = $q->header( |
|
74 | + -type => 'text/html', |
|
75 | + -charset => 'utf-8', |
|
82 | 76 | ); |
83 | 77 | |
84 | -my @SizeList = ( |
|
85 | - { 'name' => 'Large', 'key' => 'RM' }, |
|
86 | - { 'name' => 'Medium', 'key' => 'L' }, |
|
87 | -# { 'name' => 'Small', 'key' => 'M' }, |
|
78 | +#my $r = requestAws( |
|
79 | +# $conf, |
|
80 | +# { Operation => 'ItemSearch', |
|
81 | +# SearchIndex => 'All', |
|
82 | +# ResponseGroup => 'ItemAttributes,Images', |
|
83 | +# ItemId => $args->{'ASIN'}, |
|
84 | +# }, |
|
85 | +#); |
|
86 | +#say Dump($r); |
|
87 | + |
|
88 | +my $detail = getDetail( $conf, $args->{'URI'} ); |
|
89 | + |
|
90 | +$tt->process( |
|
91 | + "form.html", |
|
92 | + { urlCgiTop => $cgiPath, |
|
93 | + args => $args, |
|
94 | + detail => $detail, |
|
95 | + shots => makeShots( $conf->{'VariableShots'} ), |
|
96 | + pages => makePages( $conf->{'PageLabels'} ), |
|
97 | + images => searchImages( $conf, $args ), |
|
98 | + }, |
|
99 | + \$out |
|
100 | +) or die( $tt->error ); |
|
101 | +print $out; |
|
102 | +``` |
|
103 | + |
|
104 | +- conf/config.yml |
|
105 | +```yaml |
|
106 | +CgiName: Amazon getImages-JP |
|
107 | +ImageUriBase: https://images-na.ssl-images-amazon.com/images/P/{ASIN}.09.{SHOT}._SC{SIZE}ZZZZZZ_.jpg |
|
108 | +NoImageUri: https://images-na.ssl-images-amazon.com/images/G/09/nav2/dp/no-image-no-ciu.gif |
|
109 | +DetailUri: https://www.amazon.co.jp/dp/{ASIN}/ |
|
110 | +CustomerImageUri: https://www.amazon.co.jp/gp/customer-media/product-gallery/{ASIN} |
|
111 | +FixShots: |
|
112 | + - Name: Main |
|
113 | + Key: MAIN |
|
114 | + - Name: Top |
|
115 | + Key: TOPP |
|
116 | + - Name: Bottom |
|
117 | + Key: BOTT |
|
118 | + - Name: Left |
|
119 | + Key: LEFT |
|
120 | + - Name: Right |
|
121 | + Key: RGHT |
|
122 | + - Name: Front |
|
123 | + Key: FRNT |
|
124 | + - Name: Back |
|
125 | + Key: BACK |
|
126 | +VariableShots: |
|
127 | + - Name: "PIECE SHOTS / 書籍以外のその他の画像" |
|
128 | + Key: PT |
|
129 | + - Name: "INTERIOR SHOTS / 書籍のその他の画像" |
|
130 | + Key: IN |
|
131 | +Sizes: |
|
132 | + - Name: Large |
|
133 | + Key: RM |
|
134 | + - Name: Medium |
|
135 | + Key: L |
|
136 | + #- Name: Small |
|
137 | + # Key: M |
|
138 | +PageStep: 10 |
|
139 | +AWS: |
|
140 | + SERVICE_URI: https://webservices.amazon.co.jp/onca/xml |
|
141 | + AWS_ACCESS_KEY_ID: <your access key> |
|
142 | + SECRET_ACCESS_KEY: <your secret key> |
|
143 | + ASSOCIATE_TAG: <your associate tag> |
|
144 | +``` |
|
145 | + |
|
146 | +- lib/TakeAmazon.pm |
|
147 | +```perl |
|
148 | +# TakeAmazon.pm |
|
149 | +# Amazon サポートモジュール |
|
150 | + |
|
151 | +package TakeAmazon; |
|
152 | + |
|
153 | +use strict; |
|
154 | +use warnings; |
|
155 | +use utf8; |
|
156 | +use feature qw(say); |
|
157 | +use Encode; |
|
158 | +use Exporter 'import'; |
|
159 | +use YAML::Syck qw(LoadFile DumpFile Dump); |
|
160 | +use Path::Class; |
|
161 | +use LWP::UserAgent; |
|
162 | +use URI::Amazon::APA; |
|
163 | +use XML::Simple; |
|
164 | +use Lingua::JA::Regular::Unicode; |
|
165 | +use lib qw( /home/Shared/lib C:/_Take/lib ); |
|
166 | +use Term::Encoding qw(term_encoding); |
|
167 | +use open ':std' => ( $^O eq 'MSWin32' ? ':locale' : ':utf8' ); |
|
168 | + |
|
169 | +$YAML::Syck::ImplicitUnicode = 1; |
|
170 | +$XML::Simple::PREFERRED_PARSER = 'XML::Parser'; |
|
171 | + |
|
172 | +our @EXPORT = qw( |
|
173 | + loadConfig startsWith |
|
174 | + makePageLabels checkArgs makeShots makePages getDetail |
|
175 | + makeAwsUri requestAws |
|
176 | + searchImages searchForShots searchForSizes |
|
88 | 177 | ); |
89 | 178 | |
90 | -my $Step = 20; |
|
91 | -my %PageLabels = (); |
|
92 | -for( my $i=0; $i * $Step < 99; ++$i){ |
|
93 | - $PageLabels{ $i } = 'PT' . substr( '0' . ( $i * $Step + 1 ), -2 ) |
|
94 | - . '-PT'. substr( '0' . ( ( $i + 1 ) * $Step ), -2 ) |
|
179 | +my $ua = LWP::UserAgent->new( keep_alive => 6 ); |
|
180 | + |
|
181 | +sub loadConfig { |
|
182 | + my $file = file(__FILE__)->absolute->dir . '/../conf/config.yml'; |
|
183 | + my $conf = LoadFile($file) or die("${file}: $!"); |
|
184 | + $conf->{'PageLabels'} = makePageLabels( $conf->{'PageStep'} ); |
|
185 | + return $conf; |
|
95 | 186 | } |
96 | -$PageLabels{ 0 } = 'Main, ' . $PageLabels{ 0 }; |
|
97 | -my $PageMax = @{ [ sort { $b <=> $a } ( keys( %PageLabels ) ) ] }[ 0 ]; |
|
98 | -$PageLabels{ $PageMax } =~ s/\d+$/99/; |
|
99 | 187 | |
100 | -my $q = new CGI; |
|
101 | -$q->charset('utf-8'); |
|
102 | -my $cgipath = $q->url( -absolute => 1 ); |
|
103 | - |
|
104 | -my $URI = $q->param( 'URI' ) || ''; |
|
105 | -my $ASIN = ''; |
|
106 | -unless ( $ASIN = $q->param( 'ASIN' ) ){ |
|
107 | - # Perl 5.10 |
|
108 | - $URI =~ /\/(dp|ASIN|product)\/(?'asin'[\w]+)/; |
|
109 | - $ASIN = $+{asin}; |
|
110 | - # Perl 5.8 |
|
111 | - #$URI =~ /\/(dp|ASIN|product)\/([\w]+)/; |
|
112 | - #$ASIN = $2; |
|
188 | +sub startsWith { |
|
189 | + my $text = shift or return; |
|
190 | + my $prefix = shift or return; |
|
191 | + return $prefix eq substr( $text, 0, length($prefix) ); |
|
192 | +} |
|
193 | + |
|
194 | +sub makePageLabels { |
|
195 | + my $step = shift || 20; |
|
196 | + my @pageLabels = map { |
|
197 | + 'PT' |
|
198 | + . substr( '0' . ( $_ * $step + 1 ), -2 ) . '-PT' |
|
199 | + . substr( '0' . ( ( $_ + 1 ) * $step ), -2 ) |
|
200 | + } ( 0 .. ( 99 / $step ) ); |
|
201 | + $pageLabels[0] = 'Main, ' . $pageLabels[0]; |
|
202 | + $pageLabels[$#pageLabels] =~ s/\d+$/99/; |
|
203 | + return [@pageLabels]; |
|
204 | +} |
|
205 | + |
|
206 | +sub checkArgs { |
|
207 | + my $conf = shift or return; |
|
208 | + my $uri = shift || ''; |
|
209 | + my $asin = shift || ''; |
|
210 | + my $shotType = shift || 0; |
|
211 | + my $page = shift || 0; |
|
212 | + my $mod = !!shift; |
|
213 | + if ( !$asin ) { |
|
214 | + $uri =~ /\/(dp|ASIN|product)\/(?<asin>[\w]+)/; |
|
215 | + $asin = $+{asin}; |
|
216 | + } |
|
217 | + if ($asin) { |
|
218 | + $uri = $conf->{'DetailUri'}; |
|
219 | + $uri =~ s/\{ASIN\}/$asin/; |
|
220 | + } |
|
221 | + if ( $shotType < 0 || $#{ $conf->{'VariableShots'} } < $shotType ) { |
|
222 | + $shotType = 0; |
|
223 | + } |
|
224 | + if ( $page < 0 || $#{ $conf->{'PageLabels'} } < $page ) { |
|
225 | + $page = 0; |
|
226 | + } |
|
227 | + return { |
|
228 | + URI => $uri, |
|
229 | + ASIN => $asin, |
|
230 | + ShotType => $shotType, |
|
231 | + Page => $page, |
|
232 | + Mod => $mod, |
|
233 | + }; |
|
234 | +} |
|
235 | + |
|
236 | +sub makeShots { |
|
237 | + my $variableShots = shift or return; |
|
238 | + my $index = 0; |
|
239 | + return [ map { { value => $index++, label => $_->{'Name'}, }; } @{$variableShots} ]; |
|
113 | 240 | } |
114 | -if ( $ASIN ){ |
|
115 | - $URI = $DetailUri; |
|
116 | - $URI =~ s/%ASIN%/$ASIN/; |
|
241 | + |
|
242 | +sub makePages { |
|
243 | + my $pageLabels = shift or return; |
|
244 | + my $index = 0; |
|
245 | + return [ map { { value => $index++, label => $_, }; } @{$pageLabels} ]; |
|
117 | 246 | } |
118 | -my $SHOT = ( $q->param( 'SHOT' ) ) ? 1 : 0; |
|
119 | -my $shottype = $ShotsVarList[ $SHOT ]; |
|
120 | 247 | |
121 | -my $PAGE = $q->param( 'PAGE' ) || 0; |
|
122 | -if ( $PAGE < 0 || $PageMax < $PAGE ){ |
|
123 | - $PAGE = 0; |
|
248 | +sub getDetail { |
|
249 | + my $conf = shift or return; |
|
250 | + my $uri = shift or return; |
|
251 | + my $r = $ua->get($uri); |
|
252 | + my $html = $r->decoded_content; |
|
253 | + $html =~ /<meta\scontent="(?<content>[^"]+)"\s+name="description"\s*\/>/; |
|
254 | + my $title = $+{'content'}; |
|
255 | + $title =~ s/^Amazon\.\S+\s*//i; |
|
256 | + $title = katakana_h2z($title); |
|
257 | + return { |
|
258 | + Title => $title || 'No Title', |
|
259 | + URI => $uri . '?tag=' . $conf->{'AWS'}{'ASSOCIATE_TAG'}, |
|
260 | + }; |
|
124 | 261 | } |
125 | 262 | |
126 | -my $MOD = $q->param( 'MOD' ) || 0; |
|
127 | - |
|
128 | -my $ua = LWP::UserAgent->new( keep_alive => ( 7 + $Step ) * 3 ); |
|
129 | - |
|
130 | -my @Anchors = (); |
|
131 | - |
|
132 | -printHeader(); |
|
133 | - |
|
134 | -if ( !$ASIN || $MOD ){ |
|
135 | - print $q->start_form( -action => $q->url ), |
|
136 | - $q->table( { -summary => 'enter ASIN and so on.', -border => 1 }, |
|
137 | - $q->Tr( |
|
138 | - $q->th( 'ASIN' ), |
|
139 | - $q->td( $q->textfield( -name => 'ASIN', -value => $ASIN ) ) |
|
140 | - ), |
|
141 | - $q->Tr( |
|
142 | - $q->th( 'URI' ), |
|
143 | - $q->td( $q->textfield( -name => 'URI', -value => $URI, -size => 80 ) ) |
|
144 | - ), |
|
145 | - $q->Tr( $q->th( 'SHOT' ), $q->td( $q->popup_menu( |
|
146 | - -name => 'SHOT', |
|
147 | - -values => [sort {$a<=>$b} keys(%ShotsTypeList)], |
|
148 | - -default => $SHOT, |
|
149 | - -labels => \%ShotsTypeList, |
|
150 | - ) ) ), |
|
151 | - $q->Tr( $q->th( 'PAGE' ), $q->td( $q->popup_menu( |
|
152 | - -name => 'PAGE', |
|
153 | - -values => [sort {$a<=>$b} keys(%PageLabels)], |
|
154 | - -default => $PAGE, |
|
155 | - -labels => \%PageLabels, |
|
156 | - ) ) ), |
|
157 | - $q->Tr( $q->td( |
|
158 | - { -colspan => 2, -align => 'center' }, |
|
159 | - $q->submit, " ", $q->reset |
|
160 | - ) ), |
|
161 | - ), |
|
162 | - $q->end_form; |
|
163 | -} else { |
|
164 | - my $u = URI::Amazon::APA->new( 'http://ecs.amazonaws.jp/onca/xml' ); |
|
165 | - $u->query_form( |
|
166 | - Service => 'AWSECommerceService', |
|
167 | - Operation => 'ItemLookup', |
|
168 | - ResponseGroup => 'ItemAttributes,Images', |
|
169 | - AssociateTag => $conf->{'ASSOCIATE_TAG'}, |
|
170 | - ItemId => $ASIN, |
|
171 | - ); |
|
172 | - $u->sign( |
|
173 | - key => $conf->{'AWS_ACCESS_KEY_ID'}, |
|
174 | - secret => $conf->{'SECRET_ACCESS_KEY'}, |
|
175 | - ); |
|
176 | - |
|
177 | - my $r = $ua->get($u); |
|
178 | - if ( $r->is_success ){ |
|
179 | - print $q->h2( 'Bibliography' ); |
|
180 | - my $content = XMLin( |
|
181 | - $r->content, |
|
182 | - ForceArray => [ |
|
183 | - 'Item', 'Error', 'DetailPageURL', 'SalesRank', 'ProductGroup', 'Title', |
|
184 | - ], |
|
185 | - KeyAttr => { 'Item' => '+ASIN', }, |
|
186 | - ); |
|
187 | - my( $title, $detailpageurl, $customerimage ); |
|
188 | - if ( my $errors = $content->{'Items'}->{'Request'}->{'Errors'}->{'Error'} ){ |
|
189 | - printErrors( $errors ); |
|
190 | - } else { |
|
191 | - my $items = $content->{'Items'}->{'Item'}; |
|
192 | - my $item = $items->{$ASIN}; |
|
193 | - $title = $item->{'ItemAttributes'}->{'Title'}; |
|
194 | - $detailpageurl = $item->{'DetailPageURL'}[0]; |
|
195 | - $detailpageurl = decode( 'utf8', uri_unescape( $detailpageurl ) ); |
|
196 | - # $detailpageurl =~ s#/[^/]+/(?=dp/)#/#; |
|
197 | - # $detailpageurl = uri_unescape( $detailpageurl ); |
|
198 | - $customerimage = $CustomerImageUri; |
|
199 | - $customerimage =~ s/%ASIN%/$ASIN/; |
|
200 | - } |
|
201 | - |
|
202 | - my $pagelabel = $PageLabels{ $PAGE }; |
|
203 | - $pagelabel =~ s/PT/$ShotsVarList[ $SHOT ]/g; |
|
204 | - print $q->table( { -summary => 'Bibliography', -border => 1 }, |
|
205 | - ( $title ) ? $q->Tr( |
|
206 | - $q->th( 'TITLE' ) , |
|
207 | - $q->td( |
|
208 | - $q->a( |
|
209 | - { -href => $detailpageurl || $URI . $conf->{'ASSOCIATE_TAG'} }, |
|
210 | - $title |
|
211 | - ), $q->br(), |
|
212 | - $q->a( { -href => $customerimage }, 'Customer Image' ) |
|
213 | - ) |
|
214 | - ) : '', |
|
215 | - $q->Tr( $q->th( 'ASIN' ), $q->td( $ASIN ) ), |
|
216 | - $q->Tr( $q->th( 'SHOT' ), $q->td( $ShotsTypeList{ $SHOT } ) ), |
|
217 | - $q->Tr( $q->th( 'PAGE' ), $q->td( $pagelabel ) ), |
|
218 | - ); |
|
219 | - |
|
220 | - print $q->h2( 'Search Results' ); |
|
221 | - $ImageUriBase =~ s/%ASIN%/$ASIN/; |
|
222 | - print $q->p( { -id => 'status' }, 'Now searching...' ); |
|
223 | - if ( $PAGE == 0 ){ |
|
224 | - foreach my $shot ( @ShotsFixList ){ |
|
225 | - my $ImageUri = $ImageUriBase; |
|
226 | - my $shotkey = $shot->{'key'}; |
|
227 | - $ImageUri =~ s/%SHOT%/$shotkey/; |
|
228 | - searchSize( $ImageUri, $shot->{'name'} ); |
|
229 | - } |
|
230 | - } |
|
231 | - for( my $i=$PAGE*$Step; $i<($PAGE+1)*$Step && $i<99; ++$i ){ |
|
232 | - my $ImageUri = $ImageUriBase; |
|
233 | - my $shotkey = $shottype . substr( '0' . ( $i + 1 ), -2 ); |
|
234 | - $ImageUri =~ s/%SHOT%/$shotkey/; |
|
235 | - searchSize( $ImageUri, $shotkey ); |
|
236 | - } |
|
237 | - if ( @Anchors ){ |
|
238 | - print $q->h2( $q->a( { -name => 'INDEX', -id => 'INDEX' }, 'Index' ) ), |
|
239 | - $q->start_ol(), |
|
240 | - $q->li( [ map { $q->a( { -href => '#' . $_ }, $_ ) } @Anchors ] ), |
|
241 | - $q->end_ol(); |
|
242 | - } else { |
|
243 | - print $q->p( $q->img( |
|
244 | - { -src => $NoImageUri, -title => 'No Image', -alt => 'No Image' } |
|
245 | - ) ); |
|
246 | - } |
|
247 | - print $q->p( $q->a( { -href => '#top', -name => 'bottom' }, 'Page Top' ) ); |
|
248 | - } else { |
|
249 | - print $q->p( $r->status_line ); |
|
250 | - } |
|
263 | +sub makeAwsUri { |
|
264 | + my $conf = shift or return; |
|
265 | + my $opt = shift or return; |
|
266 | + my $aws = $conf->{'AWS'}; |
|
267 | + my $u = URI::Amazon::APA->new( $aws->{'SERVICE_URI'} ); |
|
268 | + $u->query_form( |
|
269 | + Service => 'AWSECommerceService', |
|
270 | + AssociateTag => $aws->{'ASSOCIATE_TAG'}, |
|
271 | + %{$opt}, |
|
272 | + ); |
|
273 | + $u->sign( |
|
274 | + key => $aws->{'AWS_ACCESS_KEY_ID'}, |
|
275 | + secret => $aws->{'SECRET_ACCESS_KEY'}, |
|
276 | + ); |
|
277 | + return $u; |
|
251 | 278 | } |
252 | 279 | |
253 | -printFooter(); |
|
254 | - |
|
255 | -exit; |
|
256 | - |
|
257 | -sub printHeader |
|
258 | -{ |
|
259 | - my $jscript = qq{ |
|
260 | - function changeStatus(){ |
|
261 | - document.getElementById('status').innerHTML = 'Finished.' |
|
262 | - + ( ( document.getElementById( 'INDEX' ) ) |
|
263 | - ? '<br><a href=\"#INDEX\">Index<'+'/a>' |
|
264 | - : '' ); |
|
265 | - } |
|
266 | - }; |
|
267 | - print $q->header(), |
|
268 | - $q->start_html( |
|
269 | - -title => $cginame, |
|
270 | - -lang => 'ja-JP', |
|
271 | - -head => [ |
|
272 | - $q->meta( { -http_equiv=>'Content-style-type', -content=>"text/css" } ), |
|
273 | - $q->meta( { -http_equiv=>'Content-script-type', -content=>"text/javascript" } ), |
|
274 | - ], |
|
275 | - -style => { 'src'=>'/take.css' }, |
|
276 | - -script => $jscript, |
|
277 | - -onLoad => 'changeStatus()', |
|
278 | - ), |
|
279 | - $q->h1( $q->a( { -name => 'top' }, $cginame ) ), |
|
280 | - $q->ul( |
|
281 | - $q->li( $q->a( { -href => $cgipath }, 'CGI Top' ) ), |
|
282 | - ( $ASIN && !$MOD ) |
|
283 | - ? $q->li( [ $q->a( { |
|
284 | - -href => "$cgipath?ASIN=$ASIN&SHOT=$SHOT&PAGE=$PAGE&MOD=1&URI=" |
|
285 | - . uri_escape_utf8( $URI ) |
|
286 | - }, 'Modify' ), ] ) |
|
287 | - : '', |
|
288 | - ); |
|
280 | +sub requestAws { |
|
281 | + my $conf = shift or return; |
|
282 | + my $opt = shift or return; |
|
283 | + my $r = $ua->get( makeAwsUri( $conf, $opt ) ); |
|
284 | + return { |
|
285 | + IsSuccess => $r->is_success, |
|
286 | + Status => $r->status_line, |
|
287 | + Content => XMLin( |
|
288 | + $r->decoded_content, |
|
289 | + ForceArray => |
|
290 | + [ 'Item', 'Error', 'DetailPageURL', 'SalesRank', 'ProductGroup', 'Title', ], |
|
291 | + KeyAttr => { 'Item' => '+ASIN', }, |
|
292 | + ), |
|
293 | + }; |
|
289 | 294 | } |
290 | 295 | |
291 | -sub printFooter |
|
292 | -{ |
|
293 | - print $q->end_html . "\n"; |
|
296 | +sub searchImages { |
|
297 | + my $conf = shift or return; |
|
298 | + my $args = shift or return; |
|
299 | + if ( !$args->{'ASIN'} ) { |
|
300 | + return; |
|
301 | + } |
|
302 | + my @images = (); |
|
303 | + my $uriBase = $conf->{'ImageUriBase'}; |
|
304 | + $uriBase =~ s/\{ASIN\}/$args->{'ASIN'}/e; |
|
305 | + if ( $args->{'Page'} == 0 ) { |
|
306 | + push( @images, searchForShots( $conf, $uriBase, $conf->{'FixShots'} ) ); |
|
307 | + } |
|
308 | + my @shots = map { |
|
309 | + my $shot |
|
310 | + = $conf->{'VariableShots'}[ $args->{'ShotType'} ]{'Key'} |
|
311 | + . substr( '0' . ( $args->{'Page'} * $conf->{'PageStep'} + $_ ), -2 ); |
|
312 | + { Name => $shot, Key => $shot, }; |
|
313 | + } ( 1 .. $conf->{'PageStep'} ); |
|
314 | + push( @images, searchForShots( $conf, $uriBase, \@shots ) ); |
|
315 | + return [@images]; |
|
294 | 316 | } |
295 | 317 | |
296 | -sub printErrors |
|
297 | -{ |
|
298 | - my( $errors ) = @_; |
|
299 | -# print $q->h2( 'Error' ); |
|
300 | - print $q->start_table( { -summary => 'Error Message', -border => 1 } ); |
|
301 | - foreach my $error ( @{$errors} ){ |
|
302 | - print $q->Tr( $q->th( $error->{'Code'} ), $q->td( $error->{'Message'} ) ); |
|
303 | - } |
|
304 | - print $q->end_table(); |
|
318 | +sub searchForShots { |
|
319 | + my $conf = shift or return; |
|
320 | + my $uriBase = shift or return; |
|
321 | + my $shots = shift or return; |
|
322 | + my @images = (); |
|
323 | + foreach my $shot ( @{$shots} ) { |
|
324 | + my $uri = $uriBase; |
|
325 | + $uri =~ s/\{SHOT\}/$shot->{'Key'}/e; |
|
326 | + if ( my $image = searchForSizes( $conf, $uri, $shot->{'Name'} ) ) { |
|
327 | + push( @images, $image ); |
|
328 | + } |
|
329 | + } |
|
330 | + return @images; |
|
305 | 331 | } |
306 | 332 | |
307 | -sub searchSize |
|
308 | -{ |
|
309 | - my( $ImageUriBase, $Shot ) = @_; |
|
310 | - foreach my $size ( @SizeList ){ |
|
311 | - my $ImageUri = $ImageUriBase; |
|
312 | - my $sizekey = $size->{'key'}; |
|
313 | - $ImageUri =~ s/%SIZE%/$sizekey/; |
|
314 | - my $title = $Shot . '_' . $size->{'name'}; |
|
315 | - #print $title . ': '; |
|
316 | - my $r = $ua->request( HTTP::Request->new( HEAD => $ImageUri ) ); |
|
317 | - if ( $r->header( 'content-type' ) eq 'image/jpeg' ){ |
|
318 | - #print 'Exist.' . $q->br(); |
|
319 | - print $q->p( |
|
320 | - $title, $q->a( { -name => $title, -href => '#INDEX' }, '*' ), $q->br(), |
|
321 | - $q->img( { -src => $ImageUri, -title => $title, -alt => $title, } ) |
|
322 | - ); |
|
323 | - push( @Anchors, $title ); |
|
324 | - last; |
|
325 | - } else { |
|
326 | - #print 'Not exist.' . $q->br(); |
|
327 | - } |
|
328 | - } |
|
333 | +sub searchForSizes { |
|
334 | + my $conf = shift or return; |
|
335 | + my $uriBase = shift or return; |
|
336 | + my $shot = shift or return; |
|
337 | + foreach my $size ( @{ $conf->{'Sizes'} } ) { |
|
338 | + my $uri = $uriBase; |
|
339 | + $uri =~ s/\{SIZE\}/$size->{'Key'}/e; |
|
340 | + my $r = $ua->get($uri); |
|
341 | + if ( $r->is_success && $r->header('content-type') eq 'image/jpeg' ) { |
|
342 | + return { Title => $shot . '_' . $size->{'Name'}, Uri => $uri, }; |
|
343 | + } |
|
344 | + } |
|
345 | + return; |
|
329 | 346 | } |
330 | 347 | |
331 | -# EOF |
|
348 | +1; |
|
349 | +``` |
|
350 | + |
|
351 | +- templates/form.html |
|
352 | +```html |
|
353 | +<!DOCTYPE html> |
|
354 | +<html lang="ja"> |
|
355 | + |
|
356 | +<head> |
|
357 | + <meta charset="UTF-8"> |
|
358 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
359 | + <meta http-equiv="X-UA-Compatible" content="ie=edge"> |
|
360 | + <link rel="stylesheet" type="text/css" href="/take.css" /> |
|
361 | + <link rel="stylesheet" type="text/css" href="/Amazon.css" /> |
|
362 | + <title>Amazon getImages-JP</title> |
|
363 | +</head> |
|
364 | + |
|
365 | +<body> |
|
366 | + <h1><a name="top" href="[% urlCgiTop %]">Amazon getImages-JP</a></h1> |
|
367 | + <div> |
|
368 | + <form method="POST" action="[% urlCgiTop %]" enctype="application/x-www-form-urlencoded"> |
|
369 | + <table> |
|
370 | + <tbody> |
|
371 | + [% IF detail %] |
|
372 | + <tr> |
|
373 | + <th>TITLE</th> |
|
374 | + <td><a href="[% detail.URI %]" target="_blank">[% detail.Title %]</a></td> |
|
375 | + </tr> |
|
376 | + [% END %] |
|
377 | + <tr> |
|
378 | + <th>ASIN</th> |
|
379 | + <td><input name="ASIN" type="text" value="[% args.ASIN %]"></td> |
|
380 | + </tr> |
|
381 | + <tr> |
|
382 | + <th>URI</th> |
|
383 | + <td><input name="URI" type="text" size="50" value="[% args.URI %]"></td> |
|
384 | + </tr> |
|
385 | + <tr> |
|
386 | + <th>SHOT</th> |
|
387 | + <td> |
|
388 | + <select name="SHOT"> |
|
389 | + [% FOREACH shot IN shots %] |
|
390 | + <option value="[% shot.value %]" [% IF shot.value==args.ShotType %] selected [% END %]>[% shot.label %] |
|
391 | + </option> |
|
392 | + [% END %] |
|
393 | + </select> |
|
394 | + </td> |
|
395 | + </tr> |
|
396 | + <tr> |
|
397 | + <th>PAGE</th> |
|
398 | + <td> |
|
399 | + <select name="PAGE"> |
|
400 | + [% FOREACH page IN pages %] |
|
401 | + <option value="[% page.value %]" [% IF page.value==args.Page %] selected [% END %]>[% page.label %] |
|
402 | + </option> |
|
403 | + [% END %] |
|
404 | + </select> |
|
405 | + </td> |
|
406 | + </tr> |
|
407 | + <tr> |
|
408 | + <td colspan="2"> |
|
409 | + <input name=".submit" type="submit"> |
|
410 | + <input name=".reset" type="reset"> |
|
411 | + </td> |
|
412 | + </tr> |
|
413 | + </tbody> |
|
414 | + </table> |
|
415 | + </form> |
|
416 | + </div> |
|
417 | + [% IF images %] |
|
418 | + <div> |
|
419 | + [% FOREACH image IN images %] |
|
420 | + <h2><a href="#top" name="[% image.Title %]">[% image.Title %]</a></h2> |
|
421 | + <img alt="[% image.Title %]" title="[% image.Title %]" src="[% image.Uri %]"> |
|
422 | + [% END %] |
|
423 | + </div> |
|
424 | + <div class="panelIndex"> |
|
425 | + <ol class="default"> |
|
426 | + [% FOREACH image IN images %] |
|
427 | + <li><a href="#[% image.Title %]">[% image.Title %]</a></li> |
|
428 | + [% END %] |
|
429 | + </ol> |
|
430 | + <p><a href="#top">Top</a></p> |
|
431 | + </div> |
|
432 | + [% END %] |
|
433 | +</body> |
|
434 | + |
|
435 | +</html> |
|
436 | +``` |
|
437 | + |
|
438 | +- Amazon.css |
|
439 | +```css |
|
440 | +/* Amazon.css */ |
|
441 | + |
|
442 | +.default { |
|
443 | + text-align: initial; |
|
444 | +} |
|
445 | + |
|
446 | +.panelIndex { |
|
447 | + position: fixed; |
|
448 | + top: 0em; |
|
449 | + right: 0em; |
|
450 | + padding: 0em 0.5em 0em 0em; |
|
451 | + text-align: right; |
|
452 | + background-color: #d0d0f0; |
|
453 | + border: solid; |
|
454 | + border-width: thin; |
|
455 | +} |
|
332 | 456 | ``` |
333 | 457 | |
334 | 458 | # リンク |
... | ... | @@ -343,4 +467,4 @@ sub searchSize |
343 | 467 | |
344 | 468 | - [CPAN:URI-Amazon-APA](http://search.cpan.org/dist/URI-Amazon-APA) |
345 | 469 | - [CPAN:CGI](http://search.cpan.org/dist/CGI) |
346 | -- [CPAN:URI](http://search.cpan.org/dist/URI) / [CPAN:URI/URI/Escape.pm](http://search.cpan.org/dist/URI/URI/Escape.pm) |
|
... | ... | \ No newline at end of file |
0 | +- [CPAN:URI](http://search.cpan.org/dist/URI) / [CPAN:URI/URI/Escape.pm](http://search.cpan.org/dist/URI/URI/Escape.pm) |