[PYTHON] Informationsextraktion aus der EDINET XBRL-Datei

Ich werde über den Teil schreiben, der Informationen aus der XBRL-Datei extrahiert, die beim letzten Mal verschoben wurde. Im Folgenden werden wir fortfahren, um Informationen zu einem bestimmten Kontoelement zu erhalten.

Referenzmaterial

Was ich getan habe

  1. Informationen zum Basislabel (Namenslink), die nicht in der Taxonomie beschrieben sind, erhalten Sie vom Übermittler über den in der .xsd-Datei beschriebenen Basislink.

Der Namenslink enthält den Namen des Kontos, und der Anzeigelink enthält Informationen zur Anzeigereihenfolge und zur hierarchischen Struktur der Elemente. Diese Informationen werden zum Extrahieren von Daten verwendet. Wenn Sie Daten in 1. erfassen, müssen Sie das Netzwerk durchlaufen. Da es viele Knoten gibt, wird viel Zeit verschwendet, wenn der Extraktionsprozess jedes Mal ausgeführt wird. Da es sich unabhängig vom Übermittler um die Informationen des gemeinsamen Teils handelt, wurden die einmal extrahierten Daten gespeichert und zur Wiederverwendung verfügbar gemacht.

Referenzcode

Genau wie beim letzten Mal werden nur die Daten extrahiert, sodass es überhaupt nicht interessant ist. ..

python


# coding: utf-8

from xbrl import XBRLParser
import os, re
import xml.etree.ElementTree as ET
from collections import defaultdict
import pandas as pd
import urllib2


class XbrlParser(XBRLParser):
    def __init__(self, xbrl_filename):
        self.xbrl_filename = xbrl_filename
        self.base_filename = xbrl_filename.replace('.xbrl','')
    
    def parse_xbrl(self,namespaces):
        result = defaultdict(dict)
        result['facts']=self.get_facts_info()
        
        label_file_name = self.base_filename+'_lab.xml'
        ET.register_namespace('','http://www.w3.org/2005/Atom')
        labels = ET.parse(label_file_name)
        
        # get enterprise taxonomy
        extended_labels = self.get_label_info(namespaces,labels)
        
        # get base link
        base_labels = self.get_base_label_info(namespaces)
        
        extended_labels = extended_labels.append(base_labels,ignore_index=True)
        result['labels'] = extended_labels
        result['presentation']=self.get_presentation_info(namespaces)
        return result

    def get_base_label_info(self,namespaces):
        base_file_path = os.getcwd()+'/base_labels/'
        if not os.path.exists(base_file_path):
            os.mkdir(base_file_path)
        base_labels = None
        
        # get common taxonomy
        for link_base in self.get_link_base(namespaces):
            file_path = base_file_path + link_base.strip().split('/')[-1]
            
            if os.path.exists(file_path):
                tmp_base_labels = pd.read_csv(file_path)
            else:
                print 'creating ', link_base, 'base label data...'
                response = urllib2.urlopen(link_base)
                html = response.read()
                ET.register_namespace('','http://www.xbrl.org/2003/linkbase')
                labels = ET.fromstring(html)
                labels = labels.findall('.//link:labelLink',namespaces=namespaces)[0]
                
                tmp_base_labels = self.get_label_info(namespaces,labels)
                tmp_base_labels.to_csv(file_path,index=False)                
            if base_labels is not None:
                base_labels = base_labels.append(tmp_base_labels,ignore_index=True)
            else:
                base_labels = tmp_base_labels
        return base_labels

    def concat_dictionary(self,dict1,dict2):
        for key in dict1.keys():
            dict1[key] = dict1[key]+dict2[key]
        return dict1
        
    def get_facts_info(self):
        """
        return(element_id, amount, context_ref, unit_ref, decimals)
        """
        # parse xbrl file
        xbrl = XBRLParser.parse(file(self.xbrl_filename)) # beautiful soup type object
        facts_dict = defaultdict(list)
        
        #print xbrl
        name_space = 'jp*'
        for node in xbrl.find_all(name=re.compile(name_space+':*')):
            if 'xsi:nil' in node.attrs:
                if node.attrs['xsi:nil']=='true':
                    continue
            
            facts_dict['element_id'].append( node.name.replace(':','_') )
            facts_dict['amount'].append( node.string )
            
            facts_dict['context_ref'].append(
                        self.get_attrib_value(node, 'contextref') )
            facts_dict['unit_ref'].append( 
                        self.get_attrib_value(node, 'unitref') )
            facts_dict['decimals'].append(
                        self.get_attrib_value(node, 'decimals') )
        return pd.DataFrame( facts_dict )
    
    def get_attrib_value(self, node, attrib):
        if attrib in node.attrs.keys():
            return node.attrs[attrib]
        else:
            return None
    
    def get_link_base(self,namespaces):
        label_file_name = self.base_filename+'.xsd'
        ET.register_namespace('','http://www.w3.org/2001/XMLSchema')
        labels = ET.parse(label_file_name)        
        linkbases = labels.findall('.//link:linkbaseRef',namespaces=namespaces)

        link_base = []
        for link_node in linkbases:
            link_href = link_node.attrib['{'+namespaces['xlink']+'}href']
            if '_lab.xml' in link_href and 'http://' in link_href:
                link_base.append(link_href) 
        return link_base
    
    def get_label_info(self, namespaces,labels):
        """
        return(element_id, label_string, lang, label_role, href)
        """
        label_dict = defaultdict(list)
        
        #label_file_name = self.base_filename+'_lab.xml'
        #ET.register_namespace('','http://www.w3.org/2005/Atom')
        #labels = ET.parse(label_file_name)
        
        for label_node in labels.findall('.//link:label',namespaces=namespaces):
            label_label = label_node.attrib['{'+namespaces['xlink']+'}label']
            
            for labelArc_node in labels.findall('.//link:labelArc',namespaces=namespaces):
                if label_label != labelArc_node.attrib['{'+namespaces['xlink']+'}to']:
                    continue
                
                for loc_node in labels.findall('.//link:loc',namespaces=namespaces):
                    loc_label = loc_node.attrib['{'+namespaces['xlink']+'}label']
                    if loc_label != labelArc_node.attrib['{'+namespaces['xlink']+'}from']:
                        continue
    
                    lang = label_node.attrib['{'+namespaces['xml']+'}lang']
                    label_role = label_node.attrib['{'+namespaces['xlink']+'}role']
                    href = loc_node.attrib['{'+namespaces['xlink']+'}href']
                    
                    label_dict['element_id'].append( href.split('#')[1].lower() )
                    label_dict['label_string'].append( label_node.text)
                    label_dict['lang'].append( lang )
                    label_dict['label_role'].append( label_role )
                    label_dict['href'].append( href )
        return pd.DataFrame( label_dict )

    def get_presentation_info(self, namespaces):
        """
        return(element_id, label_string, lang, label_role, href)
        """
        type_dict = defaultdict(list)
        
        label_file_name = self.base_filename+'_pre.xml'
        ET.register_namespace('','http://www.w3.org/2005/Atom')
        types = ET.parse(label_file_name)
        
        for type_link_node in types.findall('.//link:presentationLink',namespaces=namespaces):
            for type_arc_node in type_link_node.findall('.//link:presentationArc',namespaces=namespaces):
                type_arc_from = type_arc_node.attrib['{'+namespaces['xlink']+'}from']
                type_arc_to = type_arc_node.attrib['{'+namespaces['xlink']+'}to']
                
                matches = 0
                for loc_node in type_link_node.findall('.//link:loc',namespaces=namespaces):
                    loc_label = loc_node.attrib['{'+namespaces['xlink']+'}label']
                    
                    if loc_label == type_arc_from:
                        if '{'+namespaces['xlink']+'}href' in loc_node.attrib.keys():
                            href_str = loc_node.attrib['{'+namespaces['xlink']+'}href']
                            type_dict['from_href'].append( href_str )
                            type_dict['from_element_id'].append( href_str.split('#')[1].lower() )
                            matches += 1
                    elif loc_label == type_arc_to:
                        if '{'+namespaces['xlink']+'}href' in loc_node.attrib.keys():
                            href_str = loc_node.attrib['{'+namespaces['xlink']+'}href']
                            type_dict['to_href'].append( href_str )
                            type_dict['to_element_id'].append( href_str.split('#')[1].lower() )
                            matches += 1                    
                    if matches==2: break
                    
                role_id = type_link_node.attrib['{'+namespaces['xlink']+'}role']
                arcrole = type_arc_node.attrib['{'+namespaces['xlink']+'}arcrole']
                order = self.get_xml_attrib_value(type_arc_node, 'order')
                closed = self.get_xml_attrib_value(type_arc_node, 'closed')
                usable = self.get_xml_attrib_value(type_arc_node, 'usable')
                context_element = self.get_xml_attrib_value(type_arc_node, 'contextElement')
                preferred_label = self.get_xml_attrib_value(type_arc_node, 'preferredLabel')
                
                type_dict['role_id'].append( role_id )
                type_dict['arcrole'].append( arcrole )
                type_dict['order'].append( order )
                type_dict['closed'].append( closed )
                type_dict['usable'].append( usable )                
                type_dict['context_element'].append( context_element )
                type_dict['preferred_label'].append( preferred_label )
        return pd.DataFrame( type_dict )

    def get_xml_attrib_value(self, node, attrib):
        if attrib in node.attrib.keys():
            return node.attrib[attrib]
        else:
            return None
            
    def extract_target_data(self, df, element_id=None, label_string=None, \
                                lang=None, label_role=None, href=None):
        if element_id is not None:
            df = df.ix[df['element_id']==element_id,:]
        if label_string is not None:
            df = df.ix[df.label_string.str.contains(label_string),:]
        if lang is not None:
            df = df.ix[df['lang']==lang,:]
        if label_role is not None:
            df = df.ix[df.label_role.str.contains(label_role),:]
        if href is not None:
            df = df.ix[df['href']==href,:]
        return df
     
    def gather_descendant(self,df,parent):
        children = df.to_element_id.ix[df.from_element_id==parent]
        return children.append( children.apply(lambda x: self.gather_descendant(df, x)) )
    
    def get_specific_account_name_info(self,dat_fi,df_descendant):
        result = None
        for label_id in df_descendant.ix[:,0].values:
            if result is None:
                result = dat_fi.ix[dat_fi.element_id==label_id,:]
            else:
                result = result.append(dat_fi.ix[dat_fi.element_id==label_id,:], ignore_index=True)
        return result
        
def main(namespaces):
    base_path = os.getcwd()+'/xbrl_files/1301/'
    _dir = 'ED2014062400389/S10025H8/XBRL/PublicDoc/'
    xbrl_filename = base_path+_dir+'jpcrp030000-asr-001_E00012-000_2014-03-31_01_2014-06-24.xbrl'

    # get data
    xp = XbrlParser(xbrl_filename)
    
    print 'getting data...'
    xbrl_persed = xp.parse_xbrl(namespaces)
    print 'done'
    
    df_xbrl_facts = xbrl_persed['facts'] #Informationen zur Definition von Betrag und Dokumentinformationen
    df_xbrl_labels = xbrl_persed['labels'] #Namenslinkinformationen
    df_xbrl_presentation = xbrl_persed['presentation'] #Linkinformationen anzeigen

    # extract labels data
    df_xbrl_labels = xp.extract_target_data(df_xbrl_labels, lang='ja') 
                            #label_role='http://www.xbrl.org/2003/role/documentation')
                            #label_role='documentation')
    
    # De-duplication of labels data
    df_xbrl_labels = df_xbrl_labels.drop_duplicates()
    
    dat_fi = pd.merge(df_xbrl_labels, df_xbrl_facts, on='element_id',how='inner')
    
    # specify duration
    dat_fi_cyi = dat_fi.ix[dat_fi.context_ref=='CurrentYearInstant'] #Stand der aktuellen Periode
    #Liquid Asset Element_Nur ID erhalten
    parent = df_xbrl_labels.element_id.ix[df_xbrl_labels.label_string.str.contains(
                            '^Umlaufvermögen$')].drop_duplicates()
    print '\n',parent,'\n' #Liquid Asset Element_ID anzeigen
    # B/Erhalten Sie nur Informationen über die liquiden Mittel von S.
    parent = 'jppfs_cor_currentassetsabstract'
    df_xbrl_ps_cbs = df_xbrl_presentation.ix[df_xbrl_presentation.role_id.str.contains('rol_ConsolidatedBalanceSheet'),:]
    #Erwerben Sie rekursiv Elemente unterhalb der untergeordneten Elemente liquider Mittel
    df_descendant = xp.gather_descendant(df_xbrl_ps_cbs,parent).dropna() # delete nan
    #Informationen nur für ein bestimmtes Konto abrufen
    df_fi_cyi_caa = xp.get_specific_account_name_info(dat_fi_cyi, df_descendant)
    #Nur Etiketten- und Mengeninformationen anzeigen
    print df_fi_cyi_caa[['label_string','amount']].drop_duplicates()
    
if __name__=='__main__':
    namespaces = {'link': 'http://www.xbrl.org/2003/linkbase',
              'xml':'http://www.w3.org/XML/1998/namespace',
              'xlink':'http://www.w3.org/1999/xlink',
              'xsi':'http://www.w3.org/2001/XMLSchema-instance'
              }
    main(namespaces)

Das Wrack, das ursprünglich versucht hat, die XBRL-Datei mit dem Paket python-xbrl zu analysieren, bleibt erhalten. Die Informationsextraktion aus .xbrl basiert auf bs4 und die anderen auf etree. .. Da die von python-xbrl erfassten Attributinformationen in Kleinbuchstaben geschrieben sind, wird auch die von etree erfasste Attributinformation entsprechend reduziert. Es ist ein verdammter Code, ja. .. Ich denke auch, dass ich den XML-Namespace irgendwo zusammen bekommen kann, aber ich konnte nicht finden, wo ich ihn extrahieren kann, also habe ich ihn manuell erstellt. Ich möchte diesen Bereich etwas effizienter gestalten. ..

Kommentar

Ich verstehe die Struktur der XBRL-Datei nicht richtig, daher denke ich, dass es viele Ineffizienzen gibt. .. Wenn Sie etwas Seltsames bemerken, würde ich es begrüßen, wenn Sie einen Kommentar abgeben könnten.

Recommended Posts

Informationsextraktion aus der EDINET XBRL-Datei
XBRL-Datei von EDINET herunterladen (persönliches Memo)
Informationen von tweet_id (Python)
Spielen Sie WAVE-Dateien von der WSL ab
Lassen Sie uns automatisch Mitarbeiterinformationen wie das Durchschnittsgehalt aus den von EDINET (5/10) veröffentlichten XBRL-Daten extrahieren.
Sammeln wir automatisch Unternehmensinformationen (XBRL-Daten) mithilfe der EDINET-API (4/10).