[餅] 餅空 blog / Blogger支店

Bloggerの使い勝手を試しつつ記す日記です。

2005-02-08

Amazon Webサービスで困ったこと

 プログラム上で、Amazonの書籍やDVDの検索、詳細、出荷時期、レビューの取得等ができるウェブサービスというAPIをAmazonは提供している。サイト側で動的な表示ができるという点で大変重宝するサービスで、各blogのAmazon plugin等はみんなこのサービスを使っているようだ。

 ウェブサービスは他にもGoogleの検索・AdWordsや、オークションのBiddersも提供しているため、プログラムさえ組めば自サイトでGoogleの検索を利用したり、AdWordsの結果を知ったりキャンペーンを作ったり、Biddersの出品物を並べたりすることができる。
 中でもAmazonが一番人気なのはアソシエイト(アフィリエイト)と組み合わせて実利に直結させることができるからだろう。最近ではMac用の独立したアプリケーションまで存在するらしい

 私も以前PHPとnusoapを使って検索できるものを試しに作ったものの、そのままほったらかしていたのだが、ついにこの機能を実装する必要が出てきてしまったので、再度Amazonウェブサービスを弄る事となった。

 取得したいデータは、「書籍名」「著者名」「新品価格」「ユーズド価格」「発送時期」「おすすめ度」「レビューした人数」で、複数のキーワードでの検索結果をマージして売れ筋ランキング順に10件分が必要。これらは、Amazon Webサービス ECS4.0だとオペレーションがItemSearch、SortがSalesRank、ResponseGroupを Medium,Reviews,Offerfull とすれば取得できる。

 …いや、できるはずだった。

 いざ PHP+nusoap.phpで取り組んでみたところ、売れ筋ランキング(SalesRank)がおかしい。ソート順をSalesRankとしても、一つ一つのデータを見てみるとSalesRankが昇順に並んでない。Google先生に聞いてみたところ、SalesRankでの結果はいつのランキングかわからないデータを元にしているらしい。
 返される結果の順序が正しいのか、一つ一つの書籍が持っているSalesRankが正しいのか判断できないが、画面に表示される順位(とも必ずしも整合しないのだが)をベースにしたいと考えて、30位までのデータを取得後、各書籍のSalesRankを元にソートする事にした。これはこれで解決した事にしよう。

 複数のキーワードで検索した場合に同じ書籍が登場する事があり、それは当たり前の事なので構わないのだが、同じ書籍なのに違うSalesRankが得られる事があった。データベースの更新時間帯だったのだろうか。この場合は、順位が上のものを優先する事にして解決。この方法だと、違う書籍でも同じ順位になる可能性があるが、そこまで厳密である必要はどこにもないので構わないだろう。

 次に大きく悩んだのは「レビュー」の扱い。ResponseGroupにReviewsをつけたり、MediumをLargeに変えると結果が返ってこない…事がある。
 検索キーワードによって結果が返ってきたり来なかったりで、このままだと正しい結果を得ることができない。例えばItemSearchでキーワードを[YMO]、mediaを[DVD]、ResponseGroupを[Reviews]にすると、結果が返ってこない。(このキーワードは一例で今回の仕事とは関係無い)
 Google先生に聞いてみたところ、レビューのテキストの中に本来使用できない文字コードが混じってしまっていてエラーが発生しているらしい。発生した場合は、ECSフォーラムにASIN番号を書き込む事により修正してもらえるとの事で、より一般的な解決策も検討中との事。また、XSLTで結果を処理している場合にも弊害が生じるらしい。とりあえずパース中にエラーとなっているようだ。…Googleでは以上の事がわかった。

 フォーラムで報告するのはやぶさかではないが、仕事なので未知のものにも対応しなければいけない。レビューが取得できないと、「おすすめ度」や「レビューした人数」を得ることができないぞ。う~ん、困った。

 私がやってみた事

1. ItemSearchでItemIdsだけ取得し、ASINを元にItemLookupでデータを一つ一つ取得しなおす。
  結果: 失敗
  Reviewsで取得し損ねると10個のデータを失うが、この方法だと
  レビューが取得できないアイテムだけ失うことになり被害は最
  小限に留められる。しかし、データが揃わない事に代わりは無
  いので意味が無い。

2. ECS4.0に問題があるのではないかと考えてECS3.0で組みなおす。
  結果: 失敗
  Largeに相当するheavyを指定するとやはり結果が返ってこない。

3. nusoap.phpをPEAR:SOAPに変えてみる。
  結果: 失敗
  ECS4.0 だと何故かparse errorが発生。PEAR:SOAPの方にバグ
  レポートもあがっているようだが、如何ともしがたい。
  ECS3.0 だとレビューが入っているデータは取得できない。

4. ECS4.0での取得をSOAPからRESTにしてみる。
  結果: 失敗?
  socketで接続してGETでパラメータを送信するとXMLな結果が
  返ってきた。レビューも取得できてる。しかし、XMLparser
  を通した時点でエラー発生。
  必要な部分だけ自前で切り出せばOKそうだが、データが沢山
  あるのでめんどくさそう。

 なかなかうまくいかず時間を無駄にしたが、4.のあとでふと思いついた。

 「取得したXMLデータの中からエラーの原因となるレビューの中身だけ削除しちゃえ!そうするとParserがちゃんと処理してくれるんでは!?」

 「いやいや、いっその事 nusoap.php でその処理をしちゃえば普通にSOAPで扱えるのでは?」

 という事で、1行追加して<Content></Content>間のデータを削除するようにしたところ、最初にやろうとした方法で必要なデータが得られることができるようになりました。今回はレビューの内容を使わないからいいんですけど、必要な時はどう処理すればいいんでしょうかね?その時は、また改めて考える事にします。

 というわけで無事に処理できるようになりましたが、とても疲れました。レビューからイケナイ文字が早くなくなることを祈ってます。または、あってもエラーにならない抜本的な対策の早期導入を望みます。

 追記(2005/2/13)
 [Amazon Web サービスがレビューの文字化けに対応]のエントリーで書きましたが、不正な文字が混ざると正しい結果が得られない不具合は、[2005-01-19バージョン]で修正され、nusoapを改造したり悩んだりすることなく正しいデータが得られるようになりました。お試しあれ。