LoginSignup
1
2

More than 1 year has passed since last update.

軽量ETLライブラリpetlを使ってみた

Posted at

Pythonの軽量ETLライブラリpetlの検証コードの紹介となります。
EDINET 書類一覧API1を用いてJSONデータを取得し、加工、テーブルおよびログを行っています。

検証コード

petltest.py
import logging
import logging.config
import yaml
import requests
import petl
import json
import MySQLdb
from collections import OrderedDict

logger = logging.getLogger(__name__)

def main():
    # JSONデータ取得(EDINET API)
    res = requests.get("https://disclosure.edinet-fsa.go.jp/api/v1/documents.json?date=2020-09-01&type=2")
    
    # resultsの配列を抽出
    jarray = json.loads(res.content)["results"]

    # ↓↓↓↓ ここからPETL ↓↓↓↓
    # JSON配列をPETLのfromdictsで必要なフィールドだけ抽出
    table_base = petl.fromdicts(jarray, header = ["docID", "edinetCode", "filerName", "docDescription", "xbrlFlag"])

    # 結果出力
    logger.debug(petl.look(table_base))

    # フラグxbrlFlagが1のレコードをフィルタリング
    table_filtered = petl.select(table_base, lambda rec: rec.xbrlFlag == '1')

    # 日付フィールドxbrl_dateを追加
    table_addfield = petl.addfield(table_filtered, "xbrl_date", "2020-09-01", 1)

    # フラグxbrl_flagのフィールドを削除
    table_cutout = petl.cutout(table_addfield, "xbrlFlag")

    # ヘッダー変更
    table_header = petl.setheader(table_cutout, ["doc_id", "xbrl_date", "edinet_code", "filer_name", "doc_description"])

    # DB登録
    conn = MySQLdb.connect(user='xxxx',passwd='xxxxxx', host='localhost', db='petltest')
    conn.cursor().execute('SET SQL_MODE=ANSI_QUOTES')
    petl.todb(table_header, conn, "edinet_docs")

    # 集約も!
    agglist = OrderedDict()
    agglist['cnt'] = len
    agglist['docs'] = "doc_id", petl.strjoin(', ')
    table_aggregate = petl.aggregate(table_header, "filer_name", agglist)

    # スタイル指定結果出力
    logger.debug(petl.look(table_aggregate, style='simple'))

    # 先頭から10件抽出
    table_head10 = petl.head(table_aggregate, 10)

    # petl.util.base.Record型リスト化(後にループで処理するためヘッダーを除去)
    table_records = petl.records(table_head10)
    logger.debug(table_records)

    # ループ処理
    for record in table_records:
        logger.debug("企業名:{},  docIDs:[{}],  {}件".format(record.get("filer_name"), record.get("docs"), record.get("cnt")))

if __name__ == "__main__":
    logging.config.dictConfig(yaml.load(open("logging.yaml").read(), Loader=yaml.SafeLoader))
    main()

結果出力(企業名は加工しています)

最初の結果出力は以下のようになります。

2022-12-15 00:15:31,287 - __main__ - DEBUG - +------------+------------+--------------+----------------+----------+
| docID      | edinetCode | filerName    | docDescription | xbrlFlag |
+============+============+==============+================+==========+
| 'S100JMSV' | None       | None         | None           | '0'      |
+------------+------------+--------------+----------------+----------+
| 'S100JM3Z' | 'E26419'   | '株式会社xxxxxx' | '変更報告書'        | '1'      |
+------------+------------+--------------+----------------+----------+
| 'S100JK18' | None       | None         | None           | '0'      |
+------------+------------+--------------+----------------+----------+
| 'S100JMTE' | None       | None         | None           | '0'      |
+------------+------------+--------------+----------------+----------+
| 'S100JLX6' | None       | None         | None           | '0'      |
+------------+------------+--------------+----------------+----------+
...

スタイル指定結果出力は以下のようになります。

2022-12-15 00:22:37,620 - __main__ - DEBUG - =====================================================================================================================  ===  ==============================
filer_name                                                                                                             cnt  docs
=====================================================================================================================  ===  ==============================
'ちxxxxxxxxxxxx株式会社'                                                                                                     2  'S100JKCF, S100JKBL'
'みxxxxxxxxxxxx株式会社'                                                                                                            1  'S100JMLT'
'アxxxxxxxxxxxx株式会社'                                                                                                      3  'S100JL21, S100JL1Z, S100JLYM'
'エxxxxxxxxxxxxLtd'                                                                                                          1  'S100JM9W'
'オxxxxxxxxxxxx株式会社'                                                                                                              3  'S100JMMD, S100JMME, S100JMMH'
=====================================================================================================================  ===  ==============================
...                                                                     

table_recordsのlogger出力は以下のようになります。

2022-12-15 00:26:08,703 - __main__ - DEBUG - 企業名:ちxxxxxxxxxxxx株式会社,  docIDs:[S100JKCF, S100JKBL],  2件
2022-12-15 00:26:08,704 - __main__ - DEBUG - 企業名:みxxxxxxxxxxxx株式会社,  docIDs:[S100JMLT],  1件
2022-12-15 00:26:08,705 - __main__ - DEBUG - 企業名:アxxxxxxxxxxxx株式会社,  docIDs:[S100JL21, S100JL1Z, S100JLYM],  3件
2022-12-15 00:26:08,706 - __main__ - DEBUG - 企業名:エxxxxxxxxxxxxLtd,  docIDs:[S100JM9W],  1件
2022-12-15 00:26:08,708 - __main__ - DEBUG - 企業名:オxxxxxxxxxxxx株式会社,  docIDs:[S100JMMD, S100JMME, S100JMMH],  3件
2022-12-15 00:26:08,709 - __main__ - DEBUG - 企業名:キxxxxxxxxxxxxカンパニー,  docIDs:[S100JMBC],  1件
2022-12-15 00:26:08,711 - __main__ - DEBUG - 企業名:ケxxxxxxxxxxxxエルエルシー,  docIDs:[S100JMRU],  1件
2022-12-15 00:26:08,712 - __main__ - DEBUG - 企業名:フxxxxxxxxxxxx株式会社,  docIDs:[S100JK45, S100JK46],  2件
2022-12-15 00:26:08,713 - __main__ - DEBUG - 企業名:フxxxxxxxxxxxx有限会社,  docIDs:[S100JMKR],  1件
2022-12-15 00:26:08,714 - __main__ - DEBUG - 企業名:三xxxxxxxxxxxx,  docIDs:[S100JMCT],  1件

テーブル出力は以下のようになります。

mysql> select * from edinet_docs limit 5;
+----+------------+----------+-------------+-----------------------------------------------------+---------------------------------------------------------------------------------------------------------------+
| id | xbrl_date  | doc_id   | edinet_code | filer_name                                          | doc_description                                                                                               |
+----+------------+----------+-------------+-----------------------------------------------------+---------------------------------------------------------------------------------------------------------------+
|  1 | 2020-09-01 | S100JM3Z | E26419      | 株式会社xxxxxxxxxxxx                                | 変更報告書                                                                                                    |
|  2 | 2020-09-01 | S100J63J | E12430      | xxxxxxxxxxxx株式会社                                | 有価証券報告書(内国投資信託受益証券)-第16期(令和1年6月1日-令和2年6月1日)                                  |
|  3 | 2020-09-01 | S100JMOQ | E32064      | xxxxxxxxxxxx有限公司                                | 変更報告書                                                                                                    |
|  4 | 2020-09-01 | S100J63F | E12430      | xxxxxxxxxxxx株式会社                                | 有価証券届出書(内国投資信託受益証券)                                                                        |
|  5 | 2020-09-01 | S100JL21 | E10677      | xxxxxxxxxxxx株式会社                                | 有価証券報告書(内国投資信託受益証券)-第5期(令和1年6月4日-令和2年6月1日)                                   |
+----+------------+----------+-------------+-----------------------------------------------------+---------------------------------------------------------------------------------------------------------------+
5 rows in set (0.00 sec)

登録に用いたテーブル

create table edinet_docs (
  id bigint not null auto_increment comment 'id',
  xbrl_date date not null,
  doc_id varchar(8) not null,
  edinet_code varchar(6),
  filer_name varchar(128),
  doc_description varchar(256),
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;

おわりに

評判通り、手軽にETL操作が出来る印象でした。
データが巨大な場合やパフォーマンスを求める場合は当ライブラリは不向きとの情報もあるため2、パフォーマンス面での検証も必要そうです。

  1. EDINET 操作ガイド等の「EDINET_API仕様書.pdf」及び「EDINET API利用規約」を参照ください。

  2. https://petl.readthedocs.io/en/stable/intro.html

1
2
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
1
2