EC2インスタンスの価格表を生成するPythonスクリプトを作成しました

2017.07.11

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

EC2の価格表を生成する必要があったので、その際のコードを公開します。以下をPythonで実装した感じです。

AWS各サービスの価格情報をスクレイピングするワンライナー

実行環境

  • Python 2.7.10

Pythonスクリプト

東京リージョンのオンデマンド価格のみ必要であったため、それ以外の情報は破棄しています。

# coding: utf-8

import json
import re
import sys
import datetime
import urllib2

def __get_price_list(url):
response = urllib2.urlopen(url)
# 最終行のcallbackしているJavaScript行を取得する
callback_line = response.readlines()[-1]
# callback処理の文字列を除去する
js_string = callback_line[len('callback('):-len(');')]
# JSONに変換するためkey部分に""を付ける
p = re.compile(r'([0-9a-zA-Z]*):')
json_string = p.sub((lambda m:'"' + m.group(1) + '":'), js_string)
price_json = json.loads(json_string)

# key: region:operating_system:instance_type, value: price のdictに変換する
prices = {}
for price_per_region in price_json['config']['regions']:
region = price_per_region['region']
if region != 'ap-northeast-1':
continue

for instance_family in price_per_region['instanceTypes']:
for instance_size in instance_family['sizes']:
instance_type = instance_size['size']
for value_column in instance_size['valueColumns']:
operating_system = value_column['name']
price = value_column['prices']['USD']
# priceが N/A の場合はリストに追加しない
if price == 'N/A':
continue

prices[region + ':' + operating_system + ':' + instance_type] = price

return prices

def main(argv):
price_list = {
'created': str(datetime.datetime.now()),
'prices': {}
}
prices = price_list['prices']
# 旧世代
prices.update(__get_price_list('http://a0.awsstatic.com/pricing/1/ec2/previous-generation/linux-od.min.js'))
prices.update(__get_price_list('http://a0.awsstatic.com/pricing/1/ec2/previous-generation/rhel-od.min.js'))
prices.update(__get_price_list('http://a0.awsstatic.com/pricing/1/ec2/previous-generation/sles-od.min.js'))
prices.update(__get_price_list('http://a0.awsstatic.com/pricing/1/ec2/previous-generation/mswin-od.min.js'))
prices.update(__get_price_list('http://a0.awsstatic.com/pricing/1/ec2/previous-generation/mswinSQL-od.min.js'))
prices.update(__get_price_list('http://a0.awsstatic.com/pricing/1/ec2/previous-generation/mswinSQLWeb-od.min.js'))
prices.update(__get_price_list('http://a0.awsstatic.com/pricing/1/ec2/previous-generation/mswinSQLEnterprise-od.min.js'))

# 現行世代
prices.update(__get_price_list('http://a0.awsstatic.com/pricing/1/ec2/linux-od.min.js'))
prices.update(__get_price_list('http://a0.awsstatic.com/pricing/1/ec2/rhel-od.min.js'))
prices.update(__get_price_list('http://a0.awsstatic.com/pricing/1/ec2/sles-od.min.js'))
prices.update(__get_price_list('http://a0.awsstatic.com/pricing/1/ec2/mswin-od.min.js'))
prices.update(__get_price_list('http://a0.awsstatic.com/pricing/1/ec2/mswinSQL-od.min.js'))
prices.update(__get_price_list('http://a0.awsstatic.com/pricing/1/ec2/mswinSQLWeb-od.min.js'))
prices.update(__get_price_list('http://a0.awsstatic.com/pricing/1/ec2/mswinSQLEnterprise-od.min.js'))

print json.dumps(price_list, sort_keys=True, indent=4)

if __name__ == "__main__":
main(sys.argv)

出力結果は以下のようになります。diffが取りやすいようにKeyでソートしてあります。

{
"created": "2017-07-11 20:11:55.347102",
"prices": {
"ap-northeast-1:linux:c1.medium": "0.158",
"ap-northeast-1:linux:c1.xlarge": "0.632",
...
"ap-northeast-1:sles:x1.16xlarge": "9.771",
"ap-northeast-1:sles:x1.32xlarge": "19.441"
}
}

Price List APIを使わないのは?

ドキュメントにも記載がある通り料金ページの方が正となっているためです。

AWS Price List API は料金詳細を参考としてのみ提供します。オファーファイルとサービスの料金ページの間に不一致がある場合、AWS はサービスの料金ページに表示されている料金を請求します。

AWS Price List API の使用 - AWS 請求情報とコスト管理

最後に

CLI上でコマンドをパイプでつなげてワンライナーでやるのはスマートな感じがしますが、ちょっと加工したい場合はPythonのようなスクリプトでやる方が簡単ですよね。参考になれば幸いです。