0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

EDINET API で、有価証券届出書の「事業等のリスク」章を取り出して語を数えるまで

0
Posted at

2026年に東京証券取引所へ新規上場した38社について、「事業等のリスク」章に20の語がそれぞれ何社に書かれているかを数えました。この記事は、その取得 → 章の抽出 → 語の集計を、他人が同じ数字を再現できる形で残すためのものです。

先に結論を書くと、1社で通った手順は、全数で3か所崩れました。 崩れた場所と直し方を順に書きます。

やったこと

  • 対象=2026年に新規上場した38社(基準日 2026年9月29日・日本取引所グループ「新規上場銘柄一覧(株式)」)。うちテクニカル上場7社を除いた31社を集計の母集団にした
  • 取得=EDINET API v2。書類一覧(documents.json)で該当書類を探し、書類取得で本文を落とす
  • 認証=Subscription-Key をクエリパラメータで渡す。キーの値は手元の設定ファイルから読む(記事には書かない)
  • 結果=章が取れたのは 37/38社(実質の新規上場 31/31・テクニカル上場 6/7)

以下のコードは、実際に回したスクリプトから要点だけを抜き出し、読みやすく簡略化したものです。

落とし穴1:上場前の会社は secCode で引けない

書類一覧には secCode(証券コード)の列があるので、試しに使った既上場の1社はこれで引けたので、同じやり方で回すつもりでした。上場前の会社では、これは全滅します。

有価証券届出書を出す時点では、その会社はまだ上場前です。書類一覧の secCode は未採番(00000) で入っています。secCode で回していたら、38社すべて0件で返っていました。

そこで、提出者名(filerName)で突き合わせました。社名から「株式会社」「(株)」「ホールディングス」などを落とした芯の名前で部分一致させます。

def core_name(name: str) -> str:
    for w in ("株式会社", "(株)", "(株)", "ホールディングス"):
        name = name.replace(w, "")
    return name.strip()

hit = [d for d in docs if core_name(target) in core_name(d["filerName"])]

落とし穴2:1社目が例外だった(届出書と有報)

全数を回し始めたとき、母集団の最初の1社の書類は docTypeCode が 120(有価証券報告書)でした。ここで私たちは「上場会社は承認日に有報を出す。届出書の解析は要らない」と書きかけました。

全数では逆でした。030(有価証券届出書)が36社、120 が1社。 31社の母集団で見ると、届出書30社・有報1社です。

1社目が、たまたま例外の側だったのです。「1社で通った」は「手順が決まった」ではありませんでした。書類の種類は決め打ちせず、030 と 120 の両方を候補に入れ、どちらが取れたかを社ごとに記録する形に変えました。

落とし穴3:「取れなかった」は「無い」ではない

書類一覧は日付で引くので、探す窓が要ります。最初は上場承認日の前後3日、次に前後14日で探しました。この窓では、テクニカル上場7社は 0/7 でした。

ここで「テクニカル上場は届出書が無い」と書きかけました。

探す範囲を承認日の150日前まで広げたら、6/7社が取れました。 提出日は承認日の48〜118日前でした。理由はつきます。持株会社化は株主総会の前に届出書を出すので、上場承認よりずっと早いのです。

実際には、窓を広げて回し直すことを手で繰り返しました。次に同じことをするなら、最初からこの形にします。

# 窓は決め打ちせず、段階的に広げて「どの窓で取れたか」を残す(手で繰り返した手順を整理した形)
for days_back in (3, 14, 150):
    found = search_documents(filer=target, start=approval - days_back, end=approval + 3)
    if found:
        record(target, window=days_back, docs=found)
        break

この件から1つ規則にしました。「取れなかった」と書くときは、どの範囲で探したかを一緒に書く。 窓を書かない「無い」は、再現できません。

章の抽出

書類取得(type=1)で落ちてくる ZIP の中から、本文 HTML(ファイル名に honbun を含む .htm)を順に開き、タグを落としてテキストにします。

章の切り出しは、見出しの文字列に頼っています。「事業等のリスク」の見出しの位置から、次の章の見出し(「経営者による財政状態」「経営上の重要な契約」「研究開発活動」「設備の状況」のうち最初に出たもの)の手前までを章としました。複数のファイルで見つかったときは、長い方を採っています。

START = "事業等のリスク"
ENDS = ("経営者による財政状態", "経営上の重要な契約", "研究開発活動", "設備の状況")

def cut_chapter(text: str) -> str:
    s = text.find(START)
    if s < 0: return ""
    ends = [text.find(e, s + len(START)) for e in ENDS]
    ends = [e for e in ends if e > 0]
    return text[s:min(ends)] if ends else text[s:]

XBRL のタグなど構造は使っていません。見出し文字列への依存は弱点なので、取れた章の文字数を全社ぶん記録し、極端に短い社が無いかを見ました。抽出が途中で切れていれば、文字数に出ます。

語の集計と、部分一致の落とし穴

集計の前に、20語を固定しました。

セキュリティ/サイバー/個人情報/情報セキュリティ/不正アクセス/情報漏えい/情報漏洩/システム障害/API/暗号化/ランサム/マルウェア/ISMS/プライバシーマーク/内部統制/クラウド/BCP/災害/法令遵守/コンプライアンス

数え方は、章のテキストに対する単純な文字列の出現回数です。社数は「1回以上出た社」。

ここに落とし穴があります。部分一致なので、「セキュリティ」は「情報セキュリティ」の中の出現も数えます。「ランサム」は「ランサムウェア」を含みます。 公開したリリースでは「『ランサム』は『ランサムウェア』を含む語として数えています」と注記しました。語を単独で数えたいなら、前後の文字を見る処理が要りますが、今回はそうしていません。

表記ゆれも別の語として数えています。「情報漏洩」6社・「情報漏えい」3社で、合算はしていません。

もう1つ、数字の意味の線を引いておきます。人の解釈は入れていません。「リスクがある」と書いたのか「対策している」と書いたのかは区別していません。だから出てくる数字は**「その語が書かれている社数」**であって、「そのリスクを認識している社数」ではありません。書いていないことは、対策をしていないことを意味しません。

再現できる形で残す

公開したのは、抽出条件・基準日・20語・集計日です。同じ手順で同じ数字が出ます。素データ(社ごとの語の回数)は JSON で手元に残しています。

一番効いた数字の例を挙げると、31社で「API」は1社(3%)、「サイバー」または「セキュリティ」は27社(87%)、「ランサム」は0社でした。当社(SecuROI)はこの結果を調査リリースとして公開しましたが、この記事で残したいのは数字ではなく手順のほうです。

まとめ

1社で通った手順は、全数で3か所崩れました。

  1. secCode は上場前の会社では使えない → filerName で突き合わせる
  2. 1社目の書類種別(120)は例外で、本線は 030 だった → 両方を候補にして記録する
  3. 窓を狭く取ると「無い」に見える → 窓を広げ、どの窓で取れたかを残す

「通った」「取れなかった」は、どの範囲で確かめたかとセットで書く。それだけで、次に同じことをする人が同じ数字にたどり着けます。


出典:EDINET 閲覧(提出)サイト( https://disclosure2.edinet-fsa.go.jp/ ) /公共データ利用規約(PDL1.0)( https://www.digital.go.jp/resources/open_data/public_data_license_v1.0 )
上記をもとに筆者が「事業等のリスク」章を抽出し、語の出現を集計した。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?