【Python】XBRLタグの無いテキストブロック内の表を抽出する(変更報告書(大量保有)の60日間取引履歴の抽出)

変更報告書の60日間取引履歴について

大量保有報告書も現在はXBRLデータが利用可能ですが、一部の要素は詳細なタグが与えられていないため、XBRLの解析だけでは内容の読み取りは困難です。その一例が、最近60日間の取引履歴表です。

上の表は、令和2年2月12日に提出された、ある企業の大株主による変更報告書です。しっかりと60日間の取引履歴について記述があるのが分かります。
この記述部分について、実際にXBRLファイルを覗いてみると、値はHTMLテキストで与えられているのが確認できました。

&lt; や&gt;といった特殊文字は<>に全置換しています

XBRLのタグ = DetailsOfAcquisitionsAndDisposalsOfStocksEtcIssuedByIssuerOfSaidStocksEtcDuringLast60DaysTextBlock
が与えられていますが、その表の詳細についてはHTMLベースでの起債になっています。
EDINETタクソノミ要素リストを確認すると、やはり60日間取引履歴の表については、テキストブロックベースでタグが与えられていますが、表の内部まで詳細にタグ指定はしていません。

この60日間取引情報をPythonで抽出する場合は、以下の工程が考えられます。

  1. XBRL読み込み

  2. タグ指定で、表に該当する部分のテキストブロックを抽出

  3. BeautifulSoupでHTMLをパースし、表情報を抽出

実際に取得する

HTMLテキストの確認

PythonでXBRLを読み込むときはArelleを利用しています。私はすでにXBRLを読み込む環境があるので、先にHTML情報を読み込めるかどうかを確認します。

import html
from bs4 import BeautifulSoup

text = '&lt;h4&gt;(5)【当該株券等の発行者の発行する株券等に関する最近60日間の取得又は処分の状況】&lt;/h4&gt;&lt;table&gt;&lt;tr&gt;&lt;td style="width:28mm;"&gt;年月日&lt;/td&gt;&lt;td class="COL_NOBR"&gt;株券等の種類&lt;/td&gt;&lt;td class="COL_NOBR"&gt;数量&lt;/td&gt;&lt;td class="COL_NOBR"&gt;割合&lt;/td&gt;&lt;td class="COL_NOBR"&gt;市場内外取引の別&lt;/td&gt;&lt;td class="COL_NOBR"&gt;取得又は処分の別&lt;/td&gt;&lt;td class="COL_NOBR"&gt;単価&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="COL_L"&gt;令和216日&lt;/td&gt;&lt;td class="COL_L"&gt;普通株式&lt;/td&gt;&lt;td class="COL_R"&gt;37,200&lt;/td&gt;&lt;td class="COL_R"&gt;0.30&lt;/td&gt;&lt;td class="COL_L"&gt;市場内&lt;/td&gt;&lt;td class="COL_L"&gt;処分&lt;/td&gt;&lt;td class="COL_R"/&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="COL_L"&gt;令和217日&lt;/td&gt;&lt;td class="COL_L"&gt;普通株式&lt;/td&gt;&lt;td class="COL_R"&gt;37,200&lt;/td&gt;&lt;td class="COL_R"&gt;0.30&lt;/td&gt;&lt;td class="COL_L"&gt;市場内&lt;/td&gt;&lt;td class="COL_L"&gt;処分&lt;/td&gt;&lt;td class="COL_R"/&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="COL_L"&gt;令和218日&lt;/td&gt;&lt;td class="COL_L"&gt;普通株式&lt;/td&gt;&lt;td class="COL_R"&gt;37,200&lt;/td&gt;&lt;td class="COL_R"&gt;0.30&lt;/td&gt;&lt;td class="COL_L"&gt;市場内&lt;/td&gt;&lt;td class="COL_L"&gt;処分&lt;/td&gt;&lt;td class="COL_R"/&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="COL_L"&gt;令和219日&lt;/td&gt;&lt;td class="COL_L"&gt;普通株式&lt;/td&gt;&lt;td class="COL_R"&gt;37,200&lt;/td&gt;&lt;td class="COL_R"&gt;0.30&lt;/td&gt;&lt;td class="COL_L"&gt;市場内&lt;/td&gt;&lt;td class="COL_L"&gt;処分&lt;/td&gt;&lt;td class="COL_R"/&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="COL_L"&gt;令和2110日&lt;/td&gt;&lt;td class="COL_L"&gt;普通株式&lt;/td&gt;&lt;td class="COL_R"&gt;37,200&lt;/td&gt;&lt;td class="COL_R"&gt;0.30&lt;/td&gt;&lt;td class="COL_L"&gt;市場内&lt;/td&gt;&lt;td class="COL_L"&gt;処分&lt;/td&gt;&lt;td class="COL_R"/&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="COL_L"&gt;令和2114日&lt;/td&gt;&lt;td class="COL_L"&gt;普通株式&lt;/td&gt;&lt;td class="COL_R"&gt;31,200&lt;/td&gt;&lt;td class="COL_R"&gt;0.25&lt;/td&gt;&lt;td class="COL_L"&gt;市場内&lt;/td&gt;&lt;td class="COL_L"&gt;処分&lt;/td&gt;&lt;td class="COL_R"/&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="COL_L"&gt;令和2115日&lt;/td&gt;&lt;td class="COL_L"&gt;普通株式&lt;/td&gt;&lt;td class="COL_R"&gt;31,200&lt;/td&gt;&lt;td class="COL_R"&gt;0.25&lt;/td&gt;&lt;td class="COL_L"&gt;市場内&lt;/td&gt;&lt;td class="COL_L"&gt;処分&lt;/td&gt;&lt;td class="COL_R"/&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="COL_L"&gt;令和2116日&lt;/td&gt;&lt;td class="COL_L"&gt;普通株式&lt;/td&gt;&lt;td class="COL_R"&gt;31,200&lt;/td&gt;&lt;td class="COL_R"&gt;0.25&lt;/td&gt;&lt;td class="COL_L"&gt;市場内&lt;/td&gt;&lt;td class="COL_L"&gt;処分&lt;/td&gt;&lt;td class="COL_R"/&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="COL_L"&gt;令和2117日&lt;/td&gt;&lt;td class="COL_L"&gt;普通株式&lt;/td&gt;&lt;td class="COL_R"&gt;20,400&lt;/td&gt;&lt;td class="COL_R"&gt;0.16&lt;/td&gt;&lt;td class="COL_L"&gt;市場内&lt;/td&gt;&lt;td class="COL_L"&gt;処分&lt;/td&gt;&lt;td class="COL_R"/&gt;&lt;/tr&gt;&lt;/table&gt;'

un_text = html.unescape(text)

print(text)
print(un_text)

エスケープシーケンスの問題があるので、1つ文字列処理を噛んでいます。
今回利用するテキスト変数は、un_textです。

>> print(text)
>> &lt;h4&gt;(5)【当該株券等の発行者の発行する株券等に関する最近60日間の取得又は処分の状況】&lt;/h4&gt;&lt;table&gt;&lt;tr&gt;&lt;td style="width:28mm;"&gt;年月日&lt;/td&gt;&lt;td class="COL_NOBR"&gt;株券等の種類&lt;/td&gt;&lt;td class="COL_NOBR"&gt;数量&lt;/td&gt;&lt;td class="COL_NOBR"&gt;割合&lt;/td&gt;&lt;td class="COL_NOBR"&gt;市場内外取引の別&lt;/td&gt;&lt;td class="COL_NOBR"&gt;取得又は処分の別&lt;/td&gt;&lt;td class="COL_NOBR"&gt;単価&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="COL_L"&gt;令和216日&lt;/td&gt;&lt;td class="COL_L"&gt;普通株式&lt;/td&gt;&lt;td class="COL_R"&gt;37,200&lt;/td&gt;&lt;td class="COL_R"&gt;0.30&lt;/td&gt;&lt;td class="COL_L"&gt;市場内&lt;/td&gt;&lt;td class="COL_L"&gt;処分&lt;/td&gt;&lt;td class="COL_R"/&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="COL_L"&gt;令和217日&lt;/td&gt;&lt;td class="COL_L"&gt;普通株式&lt;/td&gt;&lt;td class="COL_R"&gt;37,200&lt;/td&gt;&lt;td class="COL_R"&gt;0.30&lt;/td&gt;&lt;td class="COL_L"&gt;市場内&lt;/td&gt;&lt;td class="COL_L"&gt;処分&lt;/td&gt;&lt;td class="COL_R"/&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="COL_L"&gt;令和218日&lt;/td&gt;&lt;td class="COL_L"&gt;普通株式&lt;/td&gt;&lt;td class="COL_R"&gt;37,200&lt;/td&gt;&lt;td class="COL_R"&gt;0.30&lt;/td&gt;&lt;td class="COL_L"&gt;市場内&lt;/td&gt;&lt;td class="COL_L"&gt;処分&lt;/td&gt;&lt;td class="COL_R"/&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="COL_L"&gt;令和219日&lt;/td&gt;&lt;td class="COL_L"&gt;普通株式&lt;/td&gt;&lt;td class="COL_R"&gt;37,200&lt;/td&gt;&lt;td class="COL_R"&gt;0.30&lt;/td&gt;&lt;td class="COL_L"&gt;市場内&lt;/td&gt;&lt;td class="COL_L"&gt;処分&lt;/td&gt;&lt;td class="COL_R"/&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="COL_L"&gt;令和2110日&lt;/td&gt;&lt;td class="COL_L"&gt;普通株式&lt;/td&gt;&lt;td class="COL_R"&gt;37,200&lt;/td&gt;&lt;td class="COL_R"&gt;0.30&lt;/td&gt;&lt;td class="COL_L"&gt;市場内&lt;/td&gt;&lt;td class="COL_L"&gt;処分&lt;/td&gt;&lt;td class="COL_R"/&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="COL_L"&gt;令和2114日&lt;/td&gt;&lt;td class="COL_L"&gt;普通株式&lt;/td&gt;&lt;td class="COL_R"&gt;31,200&lt;/td&gt;&lt;td class="COL_R"&gt;0.25&lt;/td&gt;&lt;td class="COL_L"&gt;市場内&lt;/td&gt;&lt;td class="COL_L"&gt;処分&lt;/td&gt;&lt;td class="COL_R"/&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="COL_L"&gt;令和2115日&lt;/td&gt;&lt;td class="COL_L"&gt;普通株式&lt;/td&gt;&lt;td class="COL_R"&gt;31,200&lt;/td&gt;&lt;td class="COL_R"&gt;0.25&lt;/td&gt;&lt;td class="COL_L"&gt;市場内&lt;/td&gt;&lt;td class="COL_L"&gt;処分&lt;/td&gt;&lt;td class="COL_R"/&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="COL_L"&gt;令和2116日&lt;/td&gt;&lt;td class="COL_L"&gt;普通株式&lt;/td&gt;&lt;td class="COL_R"&gt;31,200&lt;/td&gt;&lt;td class="COL_R"&gt;0.25&lt;/td&gt;&lt;td class="COL_L"&gt;市場内&lt;/td&gt;&lt;td class="COL_L"&gt;処分&lt;/td&gt;&lt;td class="COL_R"/&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="COL_L"&gt;令和2117日&lt;/td&gt;&lt;td class="COL_L"&gt;普通株式&lt;/td&gt;&lt;td class="COL_R"&gt;20,400&lt;/td&gt;&lt;td class="COL_R"&gt;0.16&lt;/td&gt;&lt;td class="COL_L"&gt;市場内&lt;/td&gt;&lt;td class="COL_L"&gt;処分&lt;/td&gt;&lt;td class="COL_R"/&gt;&lt;/tr&gt;&lt;/table&gt;

>> print(un_text)
>> <h4>(5)【当該株券等の発行者の発行する株券等に関する最近60日間の取得又は処分の状況】</h4><table><tr><td style="width:28mm;">年月日</td><td class="COL_NOBR">株券等の種類</td><td class="COL_NOBR">数量</td><td class="COL_NOBR">割合</td><td class="COL_NOBR">市場内外取引の別</td><td class="COL_NOBR">取得又は処分の別</td><td class="COL_NOBR">単価</td></tr><tr><td class="COL_L">令和216日</td><td class="COL_L">普通株式</td><td class="COL_R">37,200</td><td class="COL_R">0.30</td><td class="COL_L">市場内</td><td class="COL_L">処分</td><td class="COL_R"/></tr><tr><td class="COL_L">令和217日</td><td class="COL_L">普通株式</td><td class="COL_R">37,200</td><td class="COL_R">0.30</td><td class="COL_L">市場内</td><td class="COL_L">処分</td><td class="COL_R"/></tr><tr><td class="COL_L">令和218日</td><td class="COL_L">普通株式</td><td class="COL_R">37,200</td><td class="COL_R">0.30</td><td class="COL_L">市場内</td><td class="COL_L">処分</td><td class="COL_R"/></tr><tr><td class="COL_L">令和219日</td><td class="COL_L">普通株式</td><td class="COL_R">37,200</td><td class="COL_R">0.30</td><td class="COL_L">市場内</td><td class="COL_L">処分</td><td class="COL_R"/></tr><tr><td class="COL_L">令和2110日</td><td class="COL_L">普通株式</td><td class="COL_R">37,200</td><td class="COL_R">0.30</td><td class="COL_L">市場内</td><td class="COL_L">処分</td><td class="COL_R"/></tr><tr><td class="COL_L">令和2114日</td><td class="COL_L">普通株式</td><td class="COL_R">31,200</td><td class="COL_R">0.25</td><td class="COL_L">市場内</td><td class="COL_L">処分</td><td class="COL_R"/></tr><tr><td class="COL_L">令和2115日</td><td class="COL_L">普通株式</td><td class="COL_R">31,200</td><td class="COL_R">0.25</td><td class="COL_L">市場内</td><td class="COL_L">処分</td><td class="COL_R"/></tr><tr><td class="COL_L">令和2116日</td><td class="COL_L">普通株式</td><td class="COL_R">31,200</td><td class="COL_R">0.25</td><td class="COL_L">市場内</td><td class="COL_L">処分</td><td class="COL_R"/></tr><tr><td class="COL_L">令和2117日</td><td class="COL_L">普通株式</td><td class="COL_R">20,400</td><td class="COL_R">0.16</td><td class="COL_L">市場内</td><td class="COL_L">処分</td><td class="COL_R"/></tr></table>

HTMLパースのテスト

soup = BeautifulSoup(un_text, 'html.parser')
table = soup.find('table')
trs = table.find_all('tr')
for tr in trs:
    for content in tr:
        print(content.text)
    print('====')

このコードでタグの要素が取得できるはずです。実行結果を確認すると、

##実行結果
年月日
株券等の種類
数量
割合
市場内外取引の別
取得又は処分の別
単価
====
令和216日
普通株式
37,200
0.30
市場内
処分

====
令和217日
普通株式
37,200
0.30
市場内
処分

。。。。。。。(以下略)

取得できているのが確認できました。

取得結果の確認

これを、手持ちの変更報告書XRBLデータすべてで繰り返し処理を行った結果、ほとんどの取引履歴を取得できた(はず、詳細な例外処理数はまだ観察していない)ようです。

変数のユニーク値をExcelから確認します。

①年月日

年月日

②株券等の種類

株券等の種類

③数量…各株数
④割合…各割合
⑤市場内外取引の別

市場内外取引の別

⑥取得または処分の別

取得または処分の別

⑦単価

単価
単価

株券ついては新株予約証券などには個別名が割り当てられているケースが有ります。普通株式では「普通株式」や「株券(普通株式)」というように表記が様々です。

単価についてはnnn.nn円と書く場合、nnn.nnだけの場合、nnn.nn円/新株予約権、と記載している場合など、さまざまなため、標準化が難しい変数です。

XBRLの取得 ~ CSV等の出力までのコードは後日掲載したいと思います。

いいなと思ったら応援しよう!