「Pythonで学ぶXBRL入門」のコードを改造してみる
XBRL入門が届いた
技術書典マーケットに出展されていたKB農園さんのPythonで学ぶXBRL入門の本が届きました。
電子版も買っていましたが、せっかくなので紙で読みたいと思い、届くまで待っていました。
XBRLが解説されている紙の本なんて貴重すぎる!
本に掲載されているコードについて
章によってはコードの解説があり、本に載っているコードはすべてgithubに掲載されています。
4章のコードを改造してみる
4章は「たくさんの有報を自動でダウンロードしよう」となっていて、掲載されているコードを実行すると実際に有価証券報告書がダウンロードできます。
仕組みとしては、特定の期間、例えば2024/5/1~2024/5/31のように指定して、その期間の書類一覧と書類そのものを一気に取得するようになっています。
私がChatGPTを使用して作成したアプリケーションもどきでは、「提出された書類の一覧」と「提出された書類の取得」の処理を分けており、自分が取得したい企業の証券コードを入力して書類を取得する形式であるため、1社ずつ取得する必要があります。
(10年分の書類一覧をデータとして持っていれば、10年分の書類を取得できるようにはしているものの、他社も同時に……という処理は行われていない)
なので、期間指定で書類ごとまとめて取得できるようになっているのはとても便利だと思います。
デメリットとしては、処理に結構時間がかかることでしょうか。1ヶ月の指定でも、大量に書類がアップされる決算期などの場合は、10分以上かかりそうです。
4章のコードを使用して実際に有価証券報告書のXBRLをダウンロードすると、zipのファイル名がドキュメントIDとなっているため、zip名だけだとわかりません。
「企業名で保存できるようプログラムを変更するのも有効でしょう」と書かれているので、さっそく改造してみることにします。
filerNameの追加
会社名をファイル名に使用するために、fileNameを使用します。
def make_doc_id_list(day_list):
securities_report_doc_list = []
for index, day in enumerate(day_list):
url = "https://disclosure.edinet-fsa.go.jp/api/v2/documents.json"
params = {"date": day.strftime("%Y-%m-%d"),
"type": 2,
"Subscription-Key": "your_subscription_key" # Subscription-Keyは自分のAPIキーを使用
}
res = requests.get(url, params=params)
json_data = res.json()
print(day)
if "results" in json_data:
for num in range(len(json_data["results"])):
ordinance_code = json_data["results"][num]["ordinanceCode"]
form_code = json_data["results"][num]["formCode"]
docinfoeditstatus = json_data["results"][num]["docInfoEditStatus"]
if ordinance_code == "010" and form_code == "030000" and docinfoeditstatus != 2:
print(json_data["results"][num]["filerName"], json_data["results"][num]["docDescription"],
json_data["results"][num]["docID"])
+ securities_report_doc_list.append({
+ "docID": json_data["results"][num]["docID"],
+ "filerName": json_data["results"][num]["filerName"]
+ })
return securities_report_doc_list
元のコードではdocID
のみが取り出されていたので、会社名であるfilerName
も取り出して辞書に入れるようにしました。
たとえば、docID
がS100UVKO
、filerName
が株式会社ライトオン
のような辞書になります。
ファイル名に不適切な文字があった場合に置換する関数の作成
ファイル名に会社名を使用するとき、もし不適切な文字があった場合は_
に置換する関数を作成しておきます。
(該当する企業があるのかわかっていないです)
この関数を使用するために、先頭行にre
を追加します。
import re
def sanitize_filename(name):
"""
ファイル名として不適切な文字を置換する関数
"""
return re.sub(r'[\\/*?:"<>|]', '_', name) # 不正な文字をアンダースコアに置換
変数名をdoc_idからdocに変更
変数名でdoc_id
を使用していましたが、filerName
も使用するようになるため、わかりやすいようにdoc
へ変更します。
def download_xbrl_in_zip(securities_report_doc_list, number_of_lists):
# ▼ダウンロードする有報を保存しておく場所を指定。もしなければフォルダを作成する。
save_dir = "/path/to/download/directory/" # あなたの保存先のパスに変更してください。
if not os.path.exists(save_dir):
os.makedirs(save_dir)
+ for index, doc in enumerate(securities_report_doc_list):
+ print(doc, ":", index + 1, "/", number_of_lists)
+ doc_id = doc["docID"]
+ filer_name = sanitize_filename(doc["filerName"]) # 社名をファイル名として使う準備
+ filename = os.path.join(save_dir, f"{filer_name}_{doc_id}.zip")
url = f"https://disclosure.edinet-fsa.go.jp/api/v2/documents/{doc_id}"
params = {"type": 1,
"Subscription-Key": "your_subscription_key" # Subscription-Keyは自分のAPIキーを使用
}
res = requests.get(url, params=params, stream=True)
try:
if res.status_code == 200:
with open(filename, 'wb') as file:
for chunk in res.iter_content(chunk_size=1024):
file.write(chunk)
print(f"Downloaded and Saved: {filename}")
except Exception as e:
print(f"Failed to download file {doc_id}, status code: {e}")
変更箇所のところについて記載します。(変数名が変わっただけで、ほぼ同じ処理です)
- forループを使用し、
securities_report_doc_list
から、1つずつdoc
を取り出します。 -
print
で処理状況がわかるようにします。
現在処理しているdoc
と、全体の中で何件目かわかるようにindex + 1
とし、さらに全体の件数をnumber_of_lists
で表示しています。 -
doc
の中からdocID
というキーで紐づいた値を取り出し、doc_id
へ格納します。 -
doc
の中から会社名であるfilerName
を取り出します。
sanitize_filename
関数を使用し、ファイル名に使用できない文字がある場合は置換します。 - ファイル名に会社名が入るようにします。
f"{filer_name}_{doc_id}.zip"
とすることで、例えば株式会社ライトオン_S100UVKO.zip
といったファイル名になります。
実行結果
試しに、12/11~12/13を入力して実行すると、複数企業の有価証券報告書が取得できることを確認できます。
start_date: 2024-12-11
end_date: 2024-12-13
2024-12-11
ジェイフロンティア株式会社 有価証券報告書-第16期(2023/06/01-2024/05/31) S100UXGJ
株式会社三菱総合研究所 有価証券報告書-第55期(2023/10/01-2024/09/30) S100UXFQ
2024-12-12
株式会社リアルゲイト 有価証券報告書-第16期(2023/10/01-2024/09/30) S100UXKQ
マルサンアイ株式会社 有価証券報告書-第73期(2023/09/21-2024/09/20) S100UX4V
2024-12-13
株式会社中央経済社ホールディングス 有価証券報告書-第87期(2023/10/01-2024/09/30) S100UXSI
株式会社マクアケ 有価証券報告書-第12期(2023/10/01-2024/09/30) S100UY2S
株式会社サイバーエージェント 有価証券報告書-第27期(2023/10/01-2024/09/30) S100UXZA
number_of_lists: 7
get_list: [{'docID': 'S100UXGJ', 'filerName': 'ジェイフロンティア株式会社'}, {'docID': 'S100UXFQ', 'filerName': '株式会社三菱総合研究所'}, {'docID': 'S100UXKQ', 'filerName': '株式会社リアルゲイト'}, {'docID': 'S100UX4V', 'filerName': 'マルサンアイ株式会社'}, {'docID': 'S100UXSI', 'filerName': '株式会社中央経済社ホールディングス'}, {'docID': 'S100UY2S', 'filerName': '株式会社マクアケ'}, {'docID': 'S100UXZA', 'filerName': '株式会社サイバーエージェント'}]
{'docID': 'S100UXGJ', 'filerName': 'ジェイフロンティア株式会社'} : 1 / 7
Downloaded and Saved: yuuhou/ジェイフロンティア株式会社_S100UXGJ.zip
{'docID': 'S100UXFQ', 'filerName': '株式会社三菱総合研究所'} : 2 / 7
Downloaded and Saved: yuuhou/株式会社三菱総合研究所_S100UXFQ.zip
{'docID': 'S100UXKQ', 'filerName': '株式会社リアルゲイト'} : 3 / 7
Downloaded and Saved: yuuhou/株式会社リアルゲイト_S100UXKQ.zip
{'docID': 'S100UX4V', 'filerName': 'マルサンアイ株式会社'} : 4 / 7
Downloaded and Saved: yuuhou/マルサンアイ株式会社_S100UX4V.zip
{'docID': 'S100UXSI', 'filerName': '株式会社中央経済社ホールディングス'} : 5 / 7
Downloaded and Saved: yuuhou/株式会社中央経済社ホールディングス_S100UXSI.zip
{'docID': 'S100UY2S', 'filerName': '株式会社マクアケ'} : 6 / 7
Downloaded and Saved: yuuhou/株式会社マクアケ_S100UY2S.zip
{'docID': 'S100UXZA', 'filerName': '株式会社サイバーエージェント'} : 7 / 7
Downloaded and Saved: yuuhou/株式会社サイバーエージェント_S100UXZA.zip
download finish
フォルダを開くと、ファイル名に社名が正しく入っていることも確認できます。
Discussion