GAEで1日毎にAmazonの情報を取得〜保存〜表示する方法

=前置き=

 ここからしばらくはPC版の無念番付で必要になった技術をまとめるエントリになる。GAEの設定は完了して、使い方は多少なりとも知っている前提で。


 まず、PC版の無念番付の最大のネックは「普通の広告から(iframeのセキュリティの都合で)色をとることができない」という部分。これがないと「日によってアイテムドロップの傾向が変わる」というギミックが動作せず、想定するような戦術や環境の変化が起こらない。これが動かないと他に考えてる「広告連動型ゲーム」もAndroidでしか遊べなくて寂しい。

 これを解決するため、今回は「Amazonの商品画像」を使うことにした。これもセキュリティの問題が少し絡むが、回避方法はいくつかある(これはまた別エントリで解説)。

 ということで、まずは一般的な処理として「Amazonから情報を取得してGAEに保存し表示する」ところまでをまとめる。

=概要=

 基本的な流れは以下のとおり。

  • AmazonAPIが使えるようにアカウントを登録する
  • GAEで商品検索〜保存部分を作成
  • 1日毎に「検索〜保存」の処理を呼び出し
  • GAEでテンプレートを使って表示

Amazonへの登録=

 これは長いので他の人の記事にお任せする。重要なのは「アフィリエイト用のアカウント」と「Product Advertising API用のアカウント」が別々で存在すること。両方の登録が必要。

=商品検索〜保存=

 GAEで商品検索〜保存までの処理は以下のようなコードになる。(KEYやTAGはAmazon登録時の情報を設定すること)


update_model.py

from google.appengine.ext import db

#保存するモデルの定義
class UpdateModel(db.Model):
	list_index = db.IntegerProperty()
	link_url = db.TextProperty() #500 chars over
	img_url = db.StringProperty()


update_amazon_ad.py

#!/usr/local/bin/python
# -*- coding: utf-8 -*-
 
from xml.etree.ElementTree import *
import bottlenose
from google.appengine.ext import db

from update_model import UpdateModel


#Amazonを検索し、XMLをテキスト→インスタンス化するところまで

AWS_KEY    = ''
SECRET_KEY = ''
ASSOCIATE_TAG = '-22'

amazon = bottlenose.Amazon(AWS_KEY, SECRET_KEY, ASSOCIATE_TAG, Region='JP')

result = amazon.ItemSearch(Keywords=u'本の名前', SearchIndex='Books', Sort='salesrank', ItemPage='1', ResponseGroup='Small,Images')
#print result

root = fromstring(result)
 


#XMLを解析してリンクURLと画像URLを抽出し保存する

xmlns = '{http://webservices.amazon.com/AWSECommerceService/2011-08-01}'
Items = root.find(xmlns+'Items')
if Items:
	list_index = 0
	for item in Items.findall(xmlns +'Item'):
		 
		#print "-"

		#リンクURL
		linkURL = item.findtext(xmlns+'DetailPageURL')
		#print linkURL

		#画像URL
		imgURL = ""
		img = None
		imageSets = item.find(xmlns+'ImageSets')
		if imageSets is not None:
			imageSet  = imageSets.find(xmlns+'ImageSet')
			if imageSet is not None:
				image     = imageSet.find(xmlns+'SmallImage')
				if image is not None:
					imgURL = image.findtext(xmlns+'URL')
					#print imgURL


		#保存
		key_name = "Key" + str(list_index)
		info = UpdateModel.get_or_insert(key_name)
		info.list_index = list_index
		info.link_url = linkURL
		info.img_url = imgURL
		info.put()

		#Inc
		list_index += 1


 重要なのは

  • bottlenoseでAmazon検索→XML取得
  • ElementTreeでXMLにアクセス(ElementTreeはデフォで使える)
  • 日本語検索のため「# -*- coding: utf-8 -*-」とか「u'〜'」の指定が必要
  • Sortはdaterank(発売日が新しい順)だと書影(画像)がまだないことが多いのでここではsalesrank(売上げ順)を使っている

あたり。


 bottlenoseは以下からインストール。Pythonのバージョンが2.7でないとエラーが出るっぽいので注意。
GitHub - lionheart/bottlenose: A Python wrapper for the Amazon Product Advertising API.



=1日毎に呼び出し=

 GAEであればcronを使って指定したタイミングでさっきのような処理を呼び出せる。

 まずはapp.yamlでさっきの処理にアクセスできるようにする。

- url: /update_amazon_ad
  script: update_amazon_ad.py
  login: admin

 ここで「login: admin」を指定することで、他の人がアクセスして勝手に呼び出せないようにしておく。パスワードさえ入れればアクセスは可能なので、手動で実行する場合には「〜/update_amazon_ad」にアクセスすればOK。


 そしてcron.yamlというのを作ってさっきのところにアクセスするようにする。

cron:
- description: Update Amazon Ad Data
  url: /update_amazon_ad
  schedule: every day 03:23
  timezone: Asia/Tokyo

 具体的な日時の設定は参考URLの方で。ここでは開いてそうな時間帯を適当に指定してみた。


 実際にcronが動いているかは、Admin ConsoleのCron Jobsを見ればOK。

=テンプレートによる表示=

 あとは保存したlink_urlとimg_urlを表示するだけ。

 テンプレートの使い方はhttps://developers.google.com/appengine/docs/python/gettingstarted/templates?hl=jaなどを参考のこと。

 ここではテンプレートとしてtemplate.htmlを使い、munen_index.pyで値を設定して返す処理を考える。


 まずはそれぞれにアクセスできるようにする。(テンプレートもscriptとして設定している点に注意)
app.yaml

- url: /munen_banduke/index.html
  script: munen_index.py

- url: /template
  script: template/(.html)


 テンプレートは元々のHTMLを元にしつつ、Amazonリンク画像を表示するため以下のような処理を追加する。
template/template.html(Amazonリンク画像の表示部分)

<!-- div_ad_listに入っている画像リンクを一通り並べる -->
{% for div_ad in div_ad_list %}
	<a href="{{div_ad.link_url}}" target="_blank">
		<img src="{{div_ad.img_url}}"/>
	</a>
{% endfor %}


 そしてそのテンプレートに値を設定して返す処理を以下のように設定する。
munen_index.py

class MainPage(webapp.RequestHandler):
	def get(self):
		#「リンクURL&画像URL」のリストを作成
		div_ad_list = []
		infos = db.GqlQuery("SELECT * FROM UpdateModel ORDER BY list_index LIMIT 5")
		for info in infos:
			div_ad = {}

			#url
			div_ad['link_url'] = info.link_url
			div_ad['img_url'] = info.img_url

			#add
			div_ad_list.append(div_ad)

		#テンプレートに渡すパラメータとして設定
		template_values = {
			'div_ad_list': div_ad_list,
		}

		#実際にテンプレートに反映して返す
		path = os.path.join(os.path.dirname(__file__), 'template', 'template.html')
		self.response.out.write(template.render(path, template_values))


 ここらへんのテンプレートやスクリプトディレクトリ配置と相互の参照がいまいちよくわかっていないので、スクリプトはRoot部分に、テンプレートはtemplateフォルダに入れることになった。ここはできればもっと改善したいところ。