6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

有価証券報告書(XBRL)から従業員数や平均年齢および勤続年数、平均年収の数値を取得する

Last updated at Posted at 2019-06-09

##従業員の状況関連のタグの新設
 前回有価証券報告書(XBRL)の「従業員の状況」のテキスト情報をbeautifulSoupでちまちまHTML構文として読み込んで、テーブル部分の箇所から単独従業員数や平均年齢、勤続年数や平均賃金等を取得する方法について考察したが、今回2019年の新しいタクソノミの定義によって、新しく単独従業員数や平均年齢、勤続年数や平均賃金のタグが新設されたとのことなので、pythonで取得できるか確認してみた。

 2019/5/31に8005スクロールが2019年3月期の有価証券報告書を提出したので、毎度おなじみの有報キャッチャーAPIを利用して、XBRLで従業員関連のタグを取得してみた。

emp.py
import requests
from bs4 import BeautifulSoup
import os
import zipfile
import re 
import xml.etree.ElementTree as ET
import pandas as pd

def fn_xbrl(sic,url):
       #XBRLダウンロード
       fn = str(sic) +".zip"
       os.system("wget -O " + str(fn) + " " + str(url))

       # ZIP解凍
       with zipfile.ZipFile( str(fn), 'r' )  as myzip:
          infos = myzip.infolist()
          for info in infos:
              base, ext = os.path.splitext(info.filename)
              if  str(base).find('Public')>0 and ext == '.xbrl':
                  myzip.extract(info.filename)
                  # XBRLパース 
                  print('' + info.filename)
                  dict = fn_parse(sic , info.filename)

def fn_srch(sic):
        # 有報キャッチャー検索
        url='http://resource.ufocatch.com/atom/edinet/query/'+str(sic)+'0'
        r = requests.get(url)
        soup = BeautifulSoup( r.text,'html.parser')
        enty = soup.find_all("entry")

        for i in enty:
              ttl=i.find_all("title")
              # 有報のXBRL
              if str(ttl).find('有価証券報告書')>-1and str(ttl).find('訂正')==-1:
                  lnks=i.find_all("link")
                  print(ttl)
                  print(lnks[0])
                  print(lnks[1])
                  url =lnks[1].get('href')
                  fn = fn_xbrl(sic, url) if url !=''else 'hoge'

def fn_parse(sic , xbrl_path):

    ### タクソノミーURLの取得(using beautiful Soup)
    ff = open( xbrl_path , "r" ,encoding="utf-8" ).read() 
    soup = BeautifulSoup( ff ,"html.parser")

    x = soup.find_all("xbrli:xbrl" )
    x = str(x)[0:2000] 
    x = x.rsplit("xmlns")

    # 該当attr(crp)の取得
    crp  =['{' + i.replace( i[0:11] ,"").rstrip(' ').replace('"',"") + '}' for i in x[1:10] if i[0:11] == ':jpcrp_cor=']
    dei  =['{' + i.replace( i[0:11] ,"").rstrip(' ').replace('"',"") + '}' for i in x[1:10] if i[0:11] == ':jpdei_cor=']
    crp,dei = crp[0] ,dei[0]

    #df=pd.DataFrame(index=[], columns=[])
    #df.to_csv('test', header=False)

    # XML項目の取得(using elementTree)
    tree = ET.parse( xbrl_path ) 
    root = tree.getroot() 

    for c1 in root:
          if c1.tag==crp+'NumberOfEmployees': 
             #連結従業員数
             if c1.get("contextRef")=="CurrentYearInstant":
                cnsl_emp = str(c1.text)
                print( cnsl_emp )
             #提出会社の従業員数
             if c1.get("contextRef")=="CurrentYearInstant_NonConsolidatedMember":
                noncnsl_emp = str(c1.text)
                print( noncnsl_emp )
          #提出会社の臨時従業員数
          if c1.tag==crp+'AverageNumberOfTemporaryWorkers': 
             if c1.get("contextRef")=="CurrentYearInstant_NonConsolidatedMember":
                noncnsl_temp_emp = str(c1.text)
                print( noncnsl_temp_emp )
          
          #提出会社の平均年齢      
          if c1.tag==crp+'AverageAgeYearsInformationAboutReportingCompanyInformationAboutEmployees': 
                avg_age = str(c1.text)
                print( avg_age  )
          #提出会社の平均勤続年数      
          if c1.tag==crp+'AverageLengthOfServiceYearsInformationAboutReportingCompanyInformationAboutEmployees': 
                avg_lgs = str(c1.text)
                print( avg_lgs  )
          #提出会社の平均年収            
          if c1.tag==crp+'AverageAnnualSalaryInformationAboutReportingCompanyInformationAboutEmployees': 
                avg_sly = str(c1.text)
                print( avg_sly  )
      
# main
if __name__ == '__main__':

      sic=8005
      fn_srch(sic)

※スクリプト実行結果↓
スクリーンショット 2019-06-09 20.42.26.png

 2019年3月期の有報(XBRL)には2019年のタクソノミで定義されたタグがあるので、平均年収等が取得できる模様。ただし2019年3月期以前の有報(XBRL)には今回新設されたタグが定義されておらず記述もないため、平均年収等は取得できない。過去分の数値は、前回調べた方法でbeautifulSoupで従業員の状況の文章をパースして値を取得する方法を用いるしかなさそうだが、今後提出される有報に関しては平均年収の取得が超絶簡単になる。(これは朗報!)

余談:大株主のタグも数年前からXBRLで定義用意されているので、大株主の名前や保有株数、保有株比率が取得可能

okb10.py
    
    # ※前半部分は上記スクリプトと共通なので割愛

    # XML項目の取得(using elementTree)
    tree = ET.parse( xbrl_path ) 
    root = tree.getroot() 

    for c1 in root:
          #大株主1位の名前
          if c1.tag==crp+'NameMajorShareholders': 
             if c1.get("contextRef")=="CurrentYearInstant_No1MajorShareholdersMember":
                okb1_name = str(c1.text)
                print( okb1_name )
          #大株主1位の住所
          if c1.tag==crp+'AddressMajorShareholders': 
             if c1.get("contextRef")=="CurrentYearInstant_No1MajorShareholdersMember":
                okb1_adrs = str(c1.text)
                print( okb1_adrs )
          #大株主1位の保有株数           
          if c1.tag==crp+'NumberOfSharesHeld': 
             if c1.get("contextRef")=="CurrentYearInstant_No1MajorShareholdersMember":
                okb1_held = str(c1.text)
                print( okb1_held )
          if c1.tag==crp+'ShareholdingRatio': 
          #大株主1位の保有株比率           
             if c1.get("contextRef")=="CurrentYearInstant_No1MajorShareholdersMember":
                okb1_ratio = str(c1.text)
                print( okb1_ratio )
      
# main
if __name__ == '__main__':

      sic=8005
      fn_srch(sic)


※スクリプト実行結果↓
スクリーンショット 2019-06-09 21.04.01.png

 大株主の上位10名はすでに数年前からタクソノミで定義されており、タグが用意されているので、普通に上記スクリプトの通り、タグを取得することが可能。
(上記では大株主1位の名前、住所、保有株数、保有比率を取得。2位以降を取得したい場合は、contextRefの値のNo1MajorShareholiders...No1の箇所を任意の数字に置き換えれば任意の順位の大株主が取得可能)

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?