28
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Pythonを使ってドルを円に変換するコマンドラインツールを作る

Last updated at Posted at 2015-07-13

概要

  1. 為替確認APIからレートのリストを取得する
  2. コマンドライン引数で受け取った値をドルから円に変換する
$ brew tap kei-sato/usdex
$ brew install usdex
$ usdex -p 2.5 -v
1(USD) => 122.54078(JPY)
2.5(USD) => 306.35195(JPY)

Gistはこちらです
https://gist.github.com/kei-sato/98675769952ec7538d6a

brew install出来るようにする方法はこちらです
Pythonで作ったコマンドラインツールをbrew install出来るようにする

解説

現在の為替情報をJSONを始めとした様々なフォーマットで公開(http://api.aoikujira.com/kawase/)してくださっている方がいらっしゃったので、これを利用して、コマンドラインからドルを円に換算するコマンドを作成しました。
まずは、APIから返ってくる値を確認します。

$ curl -s http://api.aoikujira.com/kawase/json/usd | jq .
{
  "result": "ok",
  "basecode": "USD",
  "update": "2015-07-13 17:41:44",
  "source": "*",
  "API_URL": "http://api.aoikujira.com/kawase/",
  ...(中略)
  "JPY": "123.44644",
  "KRW": "1131.46557",
  "HKD": "7.75138",
  ...(中略)
  "LBP": "1514.20449"
}

JPYに1ドルを円換算した値が入っているのが分かります。(他にもKRW(ウォン)やHKD(香港ドル)もありますね)
とりあえず、この値を抜き取って、引数で与えられた数値に掛けあわせるだけの、簡単なスクリプトを書いてみます。

exchange1.py
#coding:utf-8

import sys
import urllib
import json

URL = "http://api.aoikujira.com/kawase/json/usd"

if __name__ == "__main__":
    price = float(sys.argv[1])

    response = urllib.urlopen(URL)
    data = json.loads(response.read())
    rate = float(data[u'JPY'])
    print "{0}(USD) => {1}(JPY)".format(1, rate)
    print "{0}(USD) => {1}(JPY)".format(price, price * rate)
$ python exchange1.py 2.5
1(USD) => 122.568(JPY)
2.5(USD) => 306.42(JPY)

引数で2.5(ドル)を与えると、306円という答えが返ってきました。
ついでに1ドルあたりの円も返しています。

目的達成ですね。
以上、終了です。

といきたいところなのですが、今回は公開したいので、もう少しマシにします。

API叩き過ぎ防止

連続でAPI叩くのも良くないので、APIへのアクセスは1日1回にしようと思います。

import urllib
import json

URL = "http://api.aoikujira.com/kawase/json/usd"
FPATH = "/tmp/exchange"


def readCache():
    with open(FPATH, 'r') as f:
        body = f.read()
    return body


def writeCache(body):
    with open(FPATH, 'w') as f:
        f.write(body)


def fetchRates():
    # fetch rate list from remote
    response = urllib.urlopen(URL)
    body = response.read()

    writeCache(body)

    return body

fetchRatesでAPIへアクセスし、writeCacheで内容をファイルに保存するようにします。
readCacheでファイルに保存された内容を読み取ります。

import os.path
from datetime import date, datetime

FPATH = "/tmp/exchange"


def hasCache():
    if os.path.isfile(FPATH):
        d = date.today()
        today = datetime.combine(d, datetime.min.time())
        mtime = datetime.fromtimestamp(os.path.getmtime(FPATH))
        if mtime > today:
            return True
    return False

hasCacheでキャッシュファイルがあるかどうか確認し、最終更新日時が今日だったら、Trueを返します。
キャッシュファイルが無いか、キャッシュファイルの最終更新日時が今日より前だったら、Falseを返します。

合わせると、次のようになります

exchange2.py
#!/usr/bin/env python

import sys
import os.path
from datetime import date, datetime
import urllib
import json

URL = "http://api.aoikujira.com/kawase/json/usd"
FPATH = "/tmp/exchange"


def hasCache():
    if os.path.isfile(FPATH):
        d = date.today()
        today = datetime.combine(d, datetime.min.time())
        mtime = datetime.fromtimestamp(os.path.getmtime(FPATH))
        if mtime > today:
            return True
    return False


def readCache():
    with open(FPATH, 'r') as f:
        body = f.read()
    return body


def writeCache(body):
    with open(FPATH, 'w') as f:
        f.write(body)


def fetchRates():
    # fetch rate list from remote
    response = urllib.urlopen(URL)
    body = response.read()

    writeCache(body)

    return body

if __name__ == "__main__":
    price = float(sys.argv[1])

    if hasCache():
        body = readCache()
    else:
        body = fetchRates()

    data = json.loads(body)
    rate = float(data[u'JPY'])
    print "{0}(USD) => {1}(JPY)".format(1, rate)
    print "{0}(USD) => {1}(JPY)".format(price, price * rate)

hasCacheがTrueを返したら、readCacheでキャッシュファイルから読み込み、Falseを返したら、fetchRatesでAPIから取得するようにしています。

コマンドラインツールっぽくしたい

argparseを使って簡単にコマンドラインツールを作ることが出来ます

options.py
#coding:utf-8

import argparse

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='convert usd to any currency.')
    parser.add_argument('-p', '--price', nargs='?', type=float, help='price', default=1.0)
    parser.add_argument('-c', '--currency', nargs='?', help='currency', default=u'JPY')
    parser.add_argument('-r', '--reverse', action='store_true', help='reverse the direction')
    parser.add_argument('-v', '--verbosity', action='count', help='increase output verbosity')

    args = parser.parse_args()
    price = args.price
    currency = args.currency
    reverse = args.reverse
    verbosity = args.verbosity

    print "price:",     price
    print "currency:",  currency
    print "reverse:",   reverse
    print "verbosity:", verbosity

上記を保存して、実行してみましょう

# 引数なし
$ python options.py
price: 1.0
currency: JPY
reverse: False
verbosity: None

# 引数つき
$ python options.py -p 2.5 -c EUR -r -vvv
price: 2.5
currency: EUR
reverse: True
verbosity: 3

# ヘルプメッセージが自動生成されている
$ python options.py -h
usage: options.py [-h] [-p [PRICE]] [-c [CURRENCY]] [-r] [-v]

convert usd to any currency.

optional arguments:
  -h, --help            show this help message and exit
  -p [PRICE], --price [PRICE]
                        price
  -c [CURRENCY], --currency [CURRENCY]
                        currency
  -r, --reverse         reverse the direction
  -v, --verbosity       increase output verbosity

簡単ですね!

ここまでの、すべてを合わせたものがGistに上がっています
https://gist.github.com/kei-sato/98675769952ec7538d6a

まとめ

  • Pythonを使ってWebAPIをコマンドラインツールに落としこむ流れを紹介しました
  • urllibとjsonで簡単にAPIを取り扱うことが出来ます
  • 過度にAPIを叩きすぎないようキャッシュをつけてあげると親切だと思います
  • argparseで簡単にコマンドラインツールが作れます
  • brew installも簡単にできます -> Pythonで作ったコマンドラインツールをbrew install出来るようにする
28
31
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?