lxmlでAmazonAPI (objectify使ってみたよ)

bonlifeです。誰かに教えられるほどPython詳しいわけじゃないですが、lxmlのobjectifyはやっぱり便利だよ、ということを伝えたい!

だけどもっとレスポンスが速い方法があるはず。
誰か教えてw

まとめ記事はこちら。(記事中のquoteはurllib2.quoteっぽい。)

lxmlのobjectifyを使うとかなり使いやすいオブジェクトが生成されます。最初(objectify.parse)のレスポンスは結構遅そうですが…。

import urllib2
from lxml import objectify

host = u'http://webservices.amazon.co.jp/onca/xml?Service=AWSECommerceService'
id   = u'&SubscriptionId=AWSのアクセスキー'
ope  = u'&Operation=ItemSearch'
res  = u'&ResponseGroup=Small,Offers,Images'

keyword = u'APOGEE'
keyword = u'&Keywords=' + urllib2.quote(keyword.encode('utf-8'))
page    = u'&Page=1'
index   = u'&SearchIndex=Music'

url = host+id+ope+res+index+page+keyword
tree = objectify.parse(urllib2.urlopen(url))
root = tree.getroot()

このrootが超便利。以下のような感じで必要な値にドット繋ぎでアクセスできます。属性万歳!

In [15]: root.Items.TotalResults
Out[15]: 28

In [16]: root.Items.Item[0].ASIN
Out[16]: 'B000YSNN9I'

In [17]: root.Items.Item[0].ItemAttributes.Title
Out[17]: 'Touch in Light'

In [18]: root.Items.Item[0].SmallImage.URL
Out[18]: 'http://ecx.images-amazon.com/images/I/01xbPPWYNBL.jpg'

In [19]: root.Items.Item[0].SmallImage.Height
Out[19]: 75

In [20]: root.Items.Item[0].SmallImage.Width
Out[20]: 75

In [21]: root.Items.Item[1].ASIN
Out[21]: 'B000J3FF6C'

個人的にはこれで満足ですが、必要な値のみを取り出して辞書にしときたい場合には以下のようにすると良いかも。

def make_item_dict(item_el):
    d = dict()
    d = {
          'asin'     : item_el.ASIN,
          'title'    : item_el.ItemAttributes.Title,
          'page_url' : item_el.DetailPageURL,
        }
    try:
        d.update({
                   'img_url'  : item_el.SmallImage.URL,
                   'height'   : item_el.SmallImage.Height,
                   'width'    : item_el.SmallImage.Width,
                 })
    except AttributeError:
        d.update({
                   'img_url'  : None,
                   'height'   : None,
                   'width'    : None,
                 })
    return d

item_list = [ make_item_dict(el) for el in root.Items.Item ]
print item_list
for i in item_list:
    for k, v in i.iteritems():
        print "%-10s : %s" % (k, v)

SmallImageがない場合があって、その時に AttributeError が出てきちゃうので、無理矢理 None をセットするように変更。…ということは、元記事のxpathでビシバシ取得した各値をmapで最後に結合するやり方だとマズイってことですね。SmallImageがないItemが含まれていた場合、関連付けがズレてしまいます。やっぱりItemのElementを取得して、それ以下から必要な情報を1個ずつ取り出す処理にした方が良さそうですね。xpathでの検索を何度も実行することになって、処理速度に影響が出そうなのが気になるところですが。findなどでも文字列のprefixとしてnamespaceを付けてあげれば無理矢理検索できるので、そっちの方が速度面ではマシかも。とかウダウダ言いながら実験してみないのがbonlifeクオリティ!