Amazon MWS を使ってASINから商品情報を取得するPythonコード

今回はMWSのAPIを使ってAmazonの現在価格やランキングなどの商品情報を取得します。プログラミング言語はPythonを使います。今回から何回かに分けてネットショップの運営に役立つツールを紹介します。


## このプログラムで取得できる情報
- 現在価格
- 現在のランキング
- 新品出品者数
- 中古出品者数



## 注意点!
- 検索には10桁のASINもしくは書籍に使われているISBN-10で使います。(JANコードなどからは次回以降に紹介します)
- アマゾンのアソシエイトのAPIとは別物です。
- MWSを利用するには**大口出品者(有料サービス)になる必要**があります。 

## 必要になる情報

- SELLER_ID
- ACCESS_KEY_ID
- ACCESS_SECRET
- MarketplaceId

*上記の開発者IDを手に入れるのに大口出品者になる必要があります。
APIの仕様はこちらから
http://docs.developer.amazonservices.com/ja_JP/dev_guide/index.html

## 実際のコード
コードが汚いのは目をつぶって下さい。

get_dataという関数に検索したいASINもしくはISBN-10の文字列を引数として渡します。
入力 "4873117380"
出力 {ASIN: [現在価格, ランキング, '新品出品者数', '中古出品者数']}


```Python:Pythonのコード
import base64
import datetime
import hashlib
import hmac
import pprint
import requests
import six
import urllib.parse

from bs4 import BeautifulSoup

# この部分を書き換えて下さい。この部分を書き換えて下さい。この部分を書き換えて下さい。この部分を書き換えて下さい。この部分を書き換えて下さい。この部分を書き換えて下さい。

AMAZON_CREDENTIAL = {
    'SELLER_ID': 'Your SELLER_ID',
    'ACCESS_KEY_ID': 'Your ACCESS_KEY_ID',
    'ACCESS_SECRET': 'Your ACCESS_SECRET',
    'MarketplaceId': 'Your MarketplaceId',
    }
DOMAIN = 'mws.amazonservices.jp'
ENDPOINT = '/Products/2011-10-01'

# この部分を書き換えて下さい。この部分を書き換えて下さい。この部分を書き換えて下さい。この部分を書き換えて下さい。この部分を書き換えて下さい。この部分を書き換えて下さい。


def get_data(search_code):
    timestamp = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
    data = {
        'AWSAccessKeyId': AMAZON_CREDENTIAL['ACCESS_KEY_ID'],
        'Action': 'GetCompetitivePricingForASIN',
        'SellerId': AMAZON_CREDENTIAL['SELLER_ID'],
        'SignatureMethod': 'HmacSHA256',
        'MarketplaceId': AMAZON_CREDENTIAL['MarketplaceId'],
        'SignatureVersion': '2',
        'Timestamp': timestamp,
        'Version': '2011-10-01',
        'ItemCondition': 'NEW',
        'ExcludeMe': 'true',
        'ASINList.ASIN.1': search_code
    }

    query_list = list()
    for k, v in sorted(data.items()):
        query_list.append('{}={}'.format(k, urllib.parse.quote(v, safe='')))
    query_string = "&".join(query_list)

    canonical = "{}\n{}\n{}\n{}".format(
        'POST', DOMAIN, ENDPOINT, query_string
    )

    h = hmac.new(
        six.b(AMAZON_CREDENTIAL['ACCESS_SECRET']),
        six.b(canonical), hashlib.sha256)

    signature = urllib.parse.quote(base64.b64encode(h.digest()), safe='')

    url = 'https://{}{}?{}&Signature={}'.format(
        DOMAIN, ENDPOINT, query_string, signature)

    response = requests.post(url)
    soup = BeautifulSoup(response.content.decode(), "lxml")
    # print(soup.prettify())

    items = soup.find_all('asin')
    result_dict = dict()

    try:
        item_data = soup.find('getcompetitivepricingforasinresult', asin=search_code)
        # print('item_data', item_data)

        # asinを取得
        try:
            result_asin = item_data.asin.text
        except Exception as err_asin:
            print(err_asin)
            result_asin = 'ASINを取得できませんでした'

        # 価格を取得
        try:
            result_price = int(round(float(item_data.amount.text)))
        except Exception as err_price:
            print(err_price)
            result_price = '価格を取得できませんでした'

        # ランクを取得
        try:
            result_rank = int(item_data.rank.text)
        except Exception as err_rank:
            print(err_rank)
            result_rank = 'ランクを取得できませんでした'

        # 新品出品者数を取得
        try:
            # result_offerlisting_new = soup.offerlistingcount
            result_offerlisting_new = item_data.find('offerlistingcount', condition='New').text
            # print('result_offerlisting', result_offerlisting_new)
        except Exception as err_result_offerlisting_new:
            print(result_offerlisting_new)
            result_offerlisting_new = '新品出品者数を取得できませんでした'

        # 中古出品者数を取得
        try:
            result_offerlisting_used = item_data.find('offerlistingcount', condition='Used').text
            # print('result_offerlisting_used', result_offerlisting_used)
        except Exception as err_result_offerlisting_used:
            # print(err_result_offerlisting_used)
            result_offerlisting_used = '中古出品者数を取得できませんでした'

        result_dict['{}'.format(result_asin)] = [result_price, result_rank, result_offerlisting_new, result_offerlisting_used]

    except Exception as err_item:
        # print(err_test)
        result_test = 'itemを取得できませんでした'

    return result_dict


if __name__ == '__main__':
    print(get_data("4873117380"))
```

## 上のコードの、下記項目を自分のMWSの情報に書き換えて下さい。
- Your SELLER_ID
- Your ACCESS_KEY_ID
- Your ACCESS_SECRET
- Your MarketplaceId

上記のコードはISBN-10で4873117380を検索していてオライリーの入門Python3のデータを取ってきます。
{'4873117380': [3956, 3621, '4', '23']}
こんな感じで返ってくれば成功です。記事を書いている現在の価格は3956円だとわかります。


## 別の商品を検索したい場合は
```Python:
if __name__ == '__main__':
    # この部分を書き換えて下さい。この部分を書き換えて下さい。
    print(get_data("検索したい ISBN-10 か ASIN"))
```

## おわりに
ここまで見ていただきありがとうございます。見てくださった誰かのお役に立てれば幸いです。もっと効率の良い方法などは探せばたくさん見つかると思います。私もわからないところは検索して継ぎ接ぎでコードを書いております。結構前に書いたので引用はわからなくなってしまっています。申し訳ありません。

### 次回以降の話
取得できるデータは上記のものだけではありません。一部データをピックアップして取得しました。絞ったんですけど、かなり長くなってしまいましたので、連続してデータを取得する場合や、JAN/EAN/UPCコードから取得する方法など次回以降に投稿したいと思います。