XBRLをダウンロードするスクリプトを改良する

前回の記事で、外部のAPIを利用してEDINETのXBRLファイルをダウンロードするスクリプトを読んだ。オリジナルのスクリプトは下記のQiita記事を参照いただきたい。qiita.com

前回の変更点

前回の記事では、オリジナルのmain関数に少しだけ変更を加えた。

if not os.path.exists(os.getcwd()+'/downloaded_info'):
    os.makedirs(os.getcwd()+'/downloaded_info')

# 中略

if not os.path.exists(os.getcwd()+'/xbrl_files/'):
    os.makedirs(os.getcwd()+'/xbrl_files/')

オリジナルではXBRLファイルの保存先として、作業ディレクトリ直下にある"xbrl_files"フォルダを、ダウンロード情報を保存するJSONファイルの保存先として作業ディレクトリ直下の"downloaded_info"フォルダを指定しているが、このフォルダが存在しない状態でスクリプトを実行した場合はエラーが発生する。
f:id:hqac:20150926163328p:plain

上記のエラーを回避するため、osモジュールを使い、もしディレクトリが存在しない場合は作るようにする。今回はさらに、このスクリプトに以下の機能を追加する。

証券コードを引数で渡す

オリジナルのスクリプトでは、main関数内のタプル型変数t_symbols証券コードを追加し、そのコードを使ってAPIへのリクエスト用URLを作成している。つまり、異なる証券コードを持つ会社の有価証券報告書を取得する場合は、main関数内のタプルを手動で修正する必要がある。取得先変更時にスクリプトを修正しなくてすむように、証券コードスクリプト呼び出し時に引数として渡すことにする。

特定期間のデータのみをダウンロードする

オリジナルのスクリプトでは、対象の証券コード有価証券報告書を(APIで取得可能なものに限り)全てダウンロードする。例えば、コード「2432」の株式会社ディー・エヌ・エーを指定した場合は、7期分の有価証券報告書を取得することができた。しかし、いつも全書類が必要なわけではない。よって、日付でダウンロード対象の期間を指定し、その期間に提出されたデータのみを取得するように変更する。

実際の変更内容

証券コードを引数で渡す

証券コードの取得には、コマンドライン引数を使うことにした。つまり、スクリプトの実行時にコマンドラインから引数を与え、その引数を使ってスクリプト内で処理を行うようにする。sysモジュールの変数sys.argvを使うと、コマンドラインから受け取った引数のリストを取り出すことができる。例えば、以下のファイルをcmd_test.pyとして保存する。

# coding: utf-8

import sys

for v in sys.argv:
    print(v)

これを以下の通り実行する。

python cmd_test.py 1 2 a b c 3 "4 5 6"

すると、以下の通り出力される。なお、コマンドライン引数リストの各要素は文字列で格納されている。
f:id:hqac:20150927112145p:plain

オリジナルのスクリプトではmain関数内のタプルからt_symbols証券コードを格納しているので、これをsys.argvから取得するように変更すればよい。また、オリジナルではタプル型を使用しているが、コマンドライン引数はリスト型で渡されるため、tuple関数を用いてsys.argvから取得したリストをタプルに変換する。

if __name__=='__main__':
    base_url = 'http://resource.ufocatch.com/atom/edinetx/query/'
    namespace = '{http://www.w3.org/2005/Atom}'
    t_symbols = tuple(sys.argv)

これで機能の追加が完了した。
スクリプトを実行する際に証券コードを引数として渡せば、対象のコードの有価証券報告書のみをダウンロードすることができる。

python xbrl_downloader.py 2432
# 株式会社ディー・エヌ・エー(証券コード: 2432)の有価証券報告書をダウンロードする

特定期間のデータのみをダウンロードする

有報キャッチャーのAPIレスポンスを見ると、有価証券報告書の提出日はupdatedタグから取得できるようだ。オリジナルのスクリプトではget_link関数でtitleタグから書類のタイトルを抽出しているので、同様にget_link関数内でel.find関数を使ってupdatedタグから提出日を抽出する。

def get_link(tree, namespace):
    #print ET.tostring(tree)
    yuho_dict = defaultdict(dict)
    for el in tree.findall('.//'+namespace+'entry'):
        title = el.find(namespace+'title').text
        date = el.find(namespace+'updated').text
        # <updated>タグから有価証券報告書の提出日を取得する
        if not is_yuho(title, date): continue
        print 'writing:',title[:30],'...'
        _id = el.find(namespace+'id').text
        link = el.find('./'+namespace+'link[@type="application/zip"]')
        url = link.attrib['href']
        yuho_dict[_id] = {'id':_id, 'title':title, 'url':url, 'date':date}
    return yuho_dict

次に、ダウンロード対象になるかどうかの条件判定はis_yuho関数で行うので、この条件に日付を追加する。Pythonで日付を扱うには、datetimeモジュールを使う。get_link関数内の変数dateで提出日の日付を取得しているので、これをdatetime.strptime関数を使ってdatetime型に変換する。詳しくはこちらの記事を参照。

def is_yuho(title, date):
    s_date = datetime.datetime.strptime(date[0:10],'%Y-%m-%d')
    u_date = datetime.date(s_date.year, s_date.month, s_date.day)
    if u'有価証券報告書' in unicode(title) and date_from <= u_date and u_date <= date_to:
        return True
    else:
        return False

datetime型の変数u_dateとdatetime型の2つの変数date_from, date_toを比較し、u_datedate_fromより大きくdate_toより小さいときにだけTrueを返すようにis_yuho関数を書き換えた。なお、date_fromdate_tomain関数内に書いておく。このパラメータはコマンドラインオプションから与えるように変更したいが、それはまた次回の課題とする。

if __name__=='__main__':
    base_url = 'http://resource.ufocatch.com/atom/edinetx/query/'
    namespace = '{http://www.w3.org/2005/Atom}'
    t_symbols = tuple(sys.argv)
    date_from = datetime.date(2014, 07, 01)
    date_to = datetime.date(2015, 06, 30)

これで機能の追加が完了した。
ダウンロード対象の期間はdate_from以降、date_to以前の日付となる。