zipを展開せずに直接読み込む方法【Python, XBRL】

Python で zip を解凍せずに直接読み込む方法です。

EDINET も TDnet も EDGAR も、XBRL は『zip ファイル』で公開されていました。

zip ファイルの中身を読み込むときは、いったん HDD か SSD に解凍(展開)するのが一般的ですが、zip から直接読み込むこともできました。

やり方ですが、『標準の zipfile モジュール』を使用したらできました。

zip の中身を SSD とかに解凍しなくていいので、大量の XBRL を読み込むときに、省スペースで済みました。

とても便利です。

もちろん、XBRL 限らず、『普通の zip ファイル』から『普通のファイル』を狙って読み込むこともできました。

標準の zipfile モジュールを使う

Python で zip ファイルを読み込むときは、Python 標準の zipfile モジュールを使います。

これで zip ファイルを開いたら、中身のファイルリストを取得するメソッド『.infolist()』と、データを読み込むメソッド『.read()』を使用することができました。

これらを使います。

zipfile モジュールのマニュアル

zipfile モジュールの Python マニュアルの場所です。

zip ファイルを開く
class zipfile.ZipFile(file, mode='r', compression=ZIP_STORED, allowZip64=True)

中身のファイルリストを取得
ZipFile.infolist()

名前を指定して読み込む
ZipFile.read(name, pwd=None)

zip を読み込む

Python で zip を読み込むコード例です。

zip を解凍せずに中身を見るには、zipfile モジュールの ZipFile() を使います。

読み込み手順

拡張子『.xbrl』のファイルだけを読み込んで辞書に入れる例です。

zipfile.ZipFile() で zip ファイルを開いてから、zip_data.infolist() でファイルリストを取得します。

ファイルリストの要素には info.filename というメンバ変数がありますので、これをzip_data.read() に渡すとデータが読み込めます。

info.filename は、実際には以下のように『フォルダ構造を含んだファイルパス』です。

'S100AM8K/XBRL/PublicDoc/jpcrp030000-asr-001_E00518-000_2017-03-31_01_2017-06-26.xbrl'

なので、ファイル名を使って読み込む・読み込まないを判定するときは、このファイルパスを意識して判定部分を作ることになります。

コード例

まず、zipfile モジュールを使う部分です。

import zipfile
from collections import OrderedDict
import traceback
def read_file_from_zip(zip_file, re_match):
    """zipからファイル名を指定して読み込む"""
    file_datas = OrderedDict()

    try:
        with zipfile.ZipFile(zip_file, 'r') as zip_data:
            # ファイルリスト取得
            infos = zip_data.infolist()

            for info in infos:
                # ファイルパスでスキップ判定
                if re_match(info.filename) is None:
                    continue

                # zipからファイルデータを読み込む
                file_data = zip_data.read(info.filename)

                # ファイルパスをキーにして辞書に入れる
                file_datas[info.filename] = file_data

    except zipfile.BadZipFile:
        print(traceback.format_exc())

    return file_datas

次に、この関数を使う部分です。メイン関数です。

zip から読み込んだデータは、そのまま lxml.etree.fromstring() に渡すことができました。データの中身はバイナリデータです。

import re
from lxml.etree import fromstring as etree_fromstring

def main():
    """メイン関数"""
    # zipファイルの場所
    zip_file = r'*****\S100AM8K.zip'

    # 拡張子でファイルを選択してみる
    re_match = re.compile('^.*?\.xbrl$').match

    # zipからファイルデータを読み込む
    files = read_file_from_zip(zip_file, re_match)

    # 読み込んだXBRLファイルを1つずつ解析
    for (file, data) in files.items():
        # ファイル名
        print('file: %s' % file)

        # XML解析 lxml.etree
        root = etree_fromstring(data)
        print('root.tag: %s' % root.tag)

        print('')
    return

あと、メイン関数を呼び出すところです。

if __name__ == '__main__':
    main()

zip から読み込んだ XML データを BeautifulSoup で読み込む場合です。バイナリデータをそのまま渡せばOKでした。

単に文字列に変換したい場合は、適当なエンコーディングを指定して『.decode()』のメソッドを呼び出します。

バイトオーダーマーク (BOM) 付きの UTF-8 をデコードするときは、'utf-8-sig' を指定します。'utf-8' でデコードしたら、先頭にパイトオーダーマークの文字列が残ってしまいました。

from bs4 import BeautifulSoup

# XML解析 BeautifulSoup(HTMLパーサー)
soup = BeautifulSoup(data, features='lxml')

# XML解析 BeautifulSoup(XMLパーサー)
soup = BeautifulSoup(data, features='xml')

# バイナリをデコードして文字列に変換
text = data.decode('utf-8-sig')

zipfile.badzipfile エラー

たくさんの zip ファイルを読み込んでいたら、時々 zipfile.badzipfile エラーに遭遇しました。

これは、zip ファイルが壊れている時に出るようでした。

データは諦めるしかないのか?

実際のところ、あくまで『Python の zipfile で読めない』というだけですので、Python 以外の解凍ソフトで読み込んだら、部分的に解凍できたという場合も結構ありました。

それから、たまにですが、何度ダウンロードしても読み込みに失敗する zip ファイルも見かけました。

サーバーの zip ファイルが壊れたまま放置されてるケースですね。米国の EDGAE XBRL の zip で時々ありました。

とりあえず、zipfile.badzipfile が出たらログに記録だけして、読めない zip はスキップするようにしてます。

処理が終わったらログを見て、読めなかった zip を再取得したりする感じですね。

基本的には、そういう対応になると思います。

Arelle で XBRL ファイルを読み込む手順

zip の中の XBRL は、Arelleアレル という Python ライブラリを使用したら、簡単に読み込むことができました。

zip から XBRL を読み込む手順です。

まず、zipfile.ZipFile() で zip ファイルを開きます。

つぎに、.infolist() で XBRL の zip ないパスを見つけます。

(例)\S100JKNH\XBRL\PublicDoc\jpcrp030000-asr-001_E00004-000_2020-05-31_01_2020-08-28.xbrl

それを、zip ファイルパスの後ろにくっつけます。

(例)F:\project\kabu\download\S100JKNH.zip\S100JKNH\XBRL\PublicDoc\jpcrp030000-asr-001_E00004-000_2020-05-31_01_2020-08-28.xbrl

これを Arelle に渡します。

これで、XBRL をパースすることができました。

Arelle は、『zip 内のほかのファイル』や『インターネット上のタクソノミ』を、自動的にたどってくれました。

なので、日本語ラベルなども、簡単に取得することができました。

Arelle の『インストール方法』や『使い方』の記事です。

【Python】Arelle のインストール方法【XBRL 読み込みライブラリ】

【Python】XBRL から『勘定科目の金額や文章』を取得するコード例【Arelle】

【Python】XBRL から『勘定科目』と『リンクベース』の内容を取得するコード例【Arelle】

タイトルとURLをコピーしました