Posted at

FRBの金利データをRSSから抜き出してみる-4

More than 1 year has passed since last update.

 前回の記事で、URLを生成するプロセスに問題があることがわかった。

 そこで、今回はJSONによるサイトマップを作成した後、JSONの形式に合わせてURL取得プログラムを変更し、モジュールを実装して正常に動作することを確認した。


作業


JSON形式の変更

まず、JSONをこのようなサイトマップ形式にした。

{

"Yield Curve":
{
"FF":"https://www.federalreserve.gov/feeds/Data/H15_H15_RIFSPFF_N.B.XML",
"M01":"https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCM01_N.B.XML",
"M03":"https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCM03_N.B.XML",
"M06":"https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCM06_N.B.XML",
"Y01":"https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCY01_N.B.XML",
"Y02":"https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCY02_N.B.XML",
"Y03":"https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCY03_N.B.XML",
"Y05":"https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCY05_N.B.XML",
"Y10":"https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCY10_N.B.XML",
"Y20":"https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCY20_N.B.XML",
"Y30":"https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCY30_N.B.XML"
}
}


プログラムの書き直し

そして、プログラムをこのように書き直した。

import json

import os
class site_map:
def __init__(self, path,filename):
#__変数で擬似ローカル変数になる
#ファイルのあるフォルダまでのパスを取得
__name = os.path.dirname(os.path.abspath(__name__))
#変換対象のjsonファイルまでのパスを作成
__path=__name+'/' + path + '/' + filename
#絶対パスに変換
__abspath=os.path.normpath(__path)

#jsonファイルを開く
__f = open(__abspath, 'r')
__jsonData=json.load(__f)

#urlの前半と後半の共通部分を取得
#__prefix=__jsonData[idx0][prefix]
#__suffix=__jsonData[idx0][suffix]

#目次を取得
__indexList = __jsonData.keys()
#dict_keyをリストに変換
__indexList=list(__indexList)

def get_index(self):
return __indexList

def get_url(self,index):
return self.urlList
#戻り値となるリストを作成
self.urlList=[]

for __num in __indexList:
#サイトマップに含まれるURLを一つづつ取得
__url=__jsonData[index][num]

#urlを生成してリストに
self.urlList.append(__url)

return self.ursList

#JSONファイルを閉じるデストラクタ。不要か?
def __del__(self):
__f.close()

a=site_map("target","siteMap.json")

さて、実行して見よう。

Traceback (most recent call last):

File "D:\Document\Visual Studio 2017\source\repos\PythonApplication2\PythonApplication2\modules\get_url.py", line 58, in <module>
print(a.get_index())
File "D:\Document\Visual Studio 2017\source\repos\PythonApplication2\PythonApplication2\modules\get_url.py", line 37, in get_index
return __indexList
NameError: name '_site_map__indexList' is not defined
Exception ignored in: <bound method site_map.__del__ of <__main__.site_map object at 0x000001EFA3D2A9E8>>
Traceback (most recent call last):
File "D:\Document\Visual Studio 2017\source\repos\PythonApplication2\PythonApplication2\modules\get_url.py", line 55, in __del__
NameError: name '_site_map__f' is not defined

動かない。どうやら、プライベート変数は同じクラス内でも関数が異なれば呼び出せないようだ。関数で呼び出す必要のある変数にselfをつけていく。あと、URLをリストに加える手続きに間違いがあったので直した。

import json

import os
class site_map:
def __init__(self, path,filename):
#__変数で擬似ローカル変数になる
#ファイルのあるフォルダまでのパスを取得
__name =str(os.path.dirname(os.path.abspath(__name__)) )
#変換対象のjsonファイルまでのパスを作成
__path=__name+'/' + path + '/' + filename
#絶対パスに変換
__abspath=os.path.normpath(__path)

#jsonファイルを開く
self.f = open(__abspath, 'r')
self.jsonData=json.load(self.f)

#urlの前半と後半の共通部分を取得
#__prefix=__jsonData[idx0][prefix]
#__suffix=__jsonData[idx0][suffix]

#目次を取得
__indexList = self.jsonData.keys()
#dict_keyをリストに変換
self.indexList=list(__indexList)

def get_index(self):
return self.indexList

def get_url(self,index):
#戻り値となるリストを作成
self.urlList=[]
__secIndex=list(self.jsonData[index].keys())
for __key in __secIndex:
#サイトマップに含まれるURLを一つづつ取得
__url=self.jsonData[index][__key]

#urlを生成してリストに
self.urlList.append(__url)

return self.urlList

#JSONファイルを閉じるデストラクタ。不要か?
def __del__(self):
self.f.close()

a=site_map("target","siteMap.json")
b=a.get_index()
print(b)
print(a.get_url(b[0]))

出力

['Yield Curve']

['https://www.federalreserve.gov/feeds/Data/H15_H15_RIFSPFF_N.B.XML', 'https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCM01_N.B.XML', 'https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCM03_N.B.XML', 'https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCM06_N.B.XML', 'https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCY01_N.B.XML', 'https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCY02_N.B.XML', 'https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCY03_N.B.XML', 'https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCY05_N.B.XML', 'https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCY10_N.B.XML', 'https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCY20_N.B.XML', 'https://www.federalreserve.gov/feeds/Data/H15_H15_RIFLGFCY30_N.B.XML']

これでOKだ。


プログラムの実装

 これに合わせて、今回のメインモジュールである、getFFRateも少し改良した。

from time import sleep

from modules import XMLprocess
from modules import get_url
import sqlite3

class get_FFRate:
#アクセスマップの入ったファイルを指定
def __init__(self,path,filename,index):
#アクセスするurlのリストを取得
__scr=get_url.site_map(path,filename)
self.urlList=__scr.get_url(index)
#日付取得用の関数
def get_date(self):
__XML=XMLprocess(self.urlList[0])
__strdate=__XML.get_cutedData("dc:date",0,10)
__XML=None
return __strdate

def get_rate(self,url):
__XML=XMLprocess(url)
__rate=__XML.get_floatData("cb:value")
__XML=None
return __rate
#urlのリストに基づいてデータを取得していく
def get_list(self):
rateList=[]
#日付をリストに入れる(主キーのつもり)
rateList.append(self.get_date())

for __url in self.urlList:
__rate=self.get_rate(__url)
rateList.append(__rate)
#1秒間待つ
sleep(1)
__XML=None
return rateList
a=get_url.site_map("target","siteMap.json")
b=a.get_index()
print(b)
for idx in b:
#今後の発展性を持たせるためのテスト
ff=get_FFRate("target","siteMap.json",idx)

print(ff.get_list())

出力:

['YieldCurve']

['2018-06-07', 1.7, 1.78, 1.94, 2.12, 2.31, 2.5, 2.63, 2.77, 2.93, 3.0, 3.08]


まとめ

 今回の改良のキモは、スクレイピングの対象をJSONファイルでコントロールできるようになったことだ。これで、getFFRateのもう一つ上位にモジュールを配置できるようになった。ただこのままだとgetFFRateのモジュールがちょっとごちゃごちゃしている気がする。

 少なくとも、親モジュールでsite_mapを呼び出しているならば、getFFRateでもう一度呼び出す理由がない。また、そのほうが他のデータを取得していく際にも使い勝手が良いだろう。モジュールをそのうち改良していきたい。

 今度は、データベースに接続してみたいと思う。

 ところで、そろそろソース管理が面倒になってきたので、今話題の「設計図管理ソフト」GitHubを使ってみたいと思っている。