写给想学Python的你:如何用Python解析XBRL

开课吧开课吧锤锤2021-04-01 16:31

    1.介绍XBRL

    美国证券交易委员会(SEC)的一个主要作用是确保投资者获得可靠的信息,以便作出决定。为此,美国证券交易委员会要求公开上市的公司提交准确描绘其财务状况的报告。公司传统上以常规文本提供这些报告,但随着计算机化股票分析的普及,SEC决定采用一种更加结构化、计算机可读的格式。

    美国证券交易委员会选择了可扩展商业报告语言(XBRL)作为结构化企业报告的格式。从2009年4月起,美国证券交易委员会要求企业除了提供文本外,还必须以XBRL格式提供财务报告。此后,印度和英国也采用XBRL格式进行企业报告。

    XBRL基于可扩展标记语言(XML),但使用特殊的标签来标记财务数据。本节介绍XML和命名空间的基础知识,然后概述XBRL。

py

    1.1XML、Schema和命名空间

    介绍XML的一个好方法是将其与HTML进行比较。HTML文档使用嵌套标签来结构其内容,这些标签的形式为<xyz>...</xyz>。例如,HTML使用<b>...</b>标签来显示粗体字的文本,如<b>Hithere!</b>。HTML允许您使用属性来控制标记的行为,例如<pid="...">...</p>中的idattribute。

    我喜欢把XML看作是通用的HTML。一个XML文档包含与HTML中类似的标签和属性,但XML并没有定义任何特定的标签或属性。相反,实现者可以通过创建模式来定义自己的标记和属性。模式是在特殊的XML文档中定义的,格式为XMLSchemaDefinition(XSD),因此,模式文档的后缀为*.xsd而不是*.xml。

    一个XML文档可以使用命名空间声明来访问模式的标签和属性。作为一个例子,下面的声明指定XML文档将访问位于http://www.example.com的模式中定义的标记和属性。

    xmlns:ex=http://www.example.com

    xmlns部分代表XML命名空间,必须存在于每个命名空间声明中。exis是可选的,作为从模式中获得的标签的前缀。例如,如果模式定义了一个名为apple的元素,那么XML文档可以使用<ex:apple>...</ex:apple>tags来访问该元素。

    1.2XBRL报告和模式

    XBRL文档是一个XML文档,它使用XBRL的标签和属性来组织其内容。这听起来似乎很简单,但一个文档可能需要访问许多不同模式的功能。例如,不同的国家有不同的报告要求,因此美国的报告与英国的报告需要使用不同的元素集。同样,不同类型的报告需要不同的模式,因此年度报告与招股说明书将使用不同的标签。

    要彻底讨论美国公司年报中的标签/属性,可能会花上一本相当大的书。在这次讨论中,我的目标是介绍一些美国报告中常见的访问的命名空间。

    1.基础XBRL模式--提供XBRL文档的整体结构。

    2.美国文件和实体信息(DEI)--设置文件的类型和特征。

    3.美国《公认会计原则》----界定了美国报告的必要内容。

    4.特定实体的模式----定义了提供报告的实体的特定要素。

    你不需要记住这些命名空间的元素,但你越熟悉,就越能从XBRL文档中提取数据。

    1.2.1 基本XBRL模式

    XBRL的基本标签和属性在位于http://www.xbrl.org/2003/instance的模式中提供。文档通常通过xbrli前缀来访问这些元素,如下文命名空间声明所示。

    xlmns:xbrli="http://www.xbrl.org/2003/instance"

    在模式定义的众多元素中,xbrli:xbrl尤为重要。这是因为每份XBRL文档的内容都必须包含在<xbrli:xbrl>...</xbrli:xbrl>标签中。

    为了理解基础模式提供的其他标签,你应该熟悉以下术语。

    -instance-一个XBRL文档,其根元素是<xbrli:xbrl>。

    -事实--报告中的个别细节,如2000万美元。

    -概念-与某一事实相关的含义,如销售商品的成本。

    -实体----概念所描述的公司或个人。

    -情境-将一个实体与一个概念联系起来的数据结构。

    许多XBRL文档首先定义了一长串上下文。每个上下文用一个<xbrli:context>元素表示,每个元素都有一个id属性。每个<xbrli:context>元素都包含一个<xbrli:entity>子元素,用来标识一个实体。以下标记定义了一个标识符为FD2013Q4YTD的上下文。

<xbrli:context id="FD2013Q4YTD">
    <xbrli:entity>
    <xbrli:identifier scheme="http://www.sec.gov/CIK">0001065088</xbrli:identifier>
  </xbrli:entity>
  <xbrli:period>
    <xbrli:startDate>2013-01-01</xbrli:startDate>
    <xbrli:endDate>2013-12-31</xbrli:endDate>
  </xbrli:period>
</xbrli:context>

通过给上下文的ID分配一个contextRef属性,文档中以后的章节可以引用这个上下文。这在下面的标记中显示出来。

<us-gaap:IncomeTaxDisclosureTextBlock 
contextRef="FD2013Q4YTD" ...>。

1.2.2  美国文件和实体信息(DEI)

    每一份提交给SEC的XBRL文件都需要提供有关其内容的信息,提交者可以通过加入美国文件和实体信息(DEI)模式的元素来满足这一要求。提交者可以通过纳入美国文件和实体信息(DEI)模式的元素来满足这一要求。这些元素通常以dei为前缀,文档可以通过以下声明来访问它们。

    xlmns:dei="http://xbrl.sec.gov/dei/2014-01-31"

    本模式中定义的元素可识别XBRL报告的类型,并提供关于提交报告的实体的信息。以下标记取自eBay的一份年度报告,演示了如何使用DEI元素。

<dei:DocumentType contextRef="..." id="Fact-...">
  10-K
</dei:DocumentType>
<dei:EntityCentralIndexKey contextRef="..." id="Fact-...">
  0001065088
</dei:EntityCentralIndexKey>
<dei:TradingSymbol contextRef="..." id="Fact-...">
  EBAY
</dei:TradingSymbol>
<dei:EntityRegistrantName contextRef="..." id="Fact-...">
  EBAY INC
</dei:EntityRegistrantName>
<dei:EntityFilerCategory contextRef="..." id="Fact-...">
  Large Accelerated Filer
</dei:EntityFilerCategory>

    如图所示,每个DEI元素都有一个id属性和一个contextRef,它指的是文档中早期定义的<xbrli:context>元素。

    1.2.3 美国公认会计原则(GAAP)

    为确保企业在会计报告中使用通用术语,美国财务会计准则委员会(FASB)提供了一套名为《公认会计原则》(GAAP)的标准。企业可以通过访问FASB的模式定义,在XBRL报告中提供GAAP数据。GAAP元素通常以us-gaap为前缀。

    xmlns:us-gaap="http://fasb.org/us-gaap/2014-01-31"

    这个模式提供了数千个与会计相关的元素,

    你可以通过搜索相应的us-gaap元素来查找报告中的会计数据。例如,eBay的2014年年报以下列标号确定其负债总额。

<code><us-gaap:Liabilities contextRef="..." decimals="..." id="..." unitRef="usd">
  25226000000
</us-gaap:Liabilities></code>

    us-gaap模式有很多元素,在名称和目的上都很相似。如果你要搜索具体的会计数据,一定不要混淆这些元素。

    2.用BeautifulSoup解析XBRL技术

    下载XBRL文档后,你可以使用多种方法提取数据。如果你知道你感兴趣的是什么元素,你可以对文本进行粗暴的搜索,比如us-gaap:Assets。在另一个极端,python-xbrl库是专门为解析XBRL文档而创建的,但我从来没有让它正常工作过。

    本节将介绍如何使用前文中介绍的BeautifulSoup包来解析XBRL。你不需要学习任何新的类或方法,但重要的是要指定你要进行XML解析。如果你安装了lxml库(pipinstalllxml),那么你可以用下面的代码创建BeautifulSoup实例。

    soup=BeautifulSoup(...,'lxml')

    出于某种原因,当我调用find_all方法搜索XBRL标记时,返回的列表总是空的。但是当我调用find_all方法时,如果没有参数,返回的列表就会包含代表XBRL标签的Tag。因此,我使用了如下的代码。

soup = BeautifulSoup(xbrl_string, 'lxml')
tag_list = soup.find_all()
for tag in tag_list:
    if tag.name == 'us-gaap:liabilities':
        print('Liabilities: ' + tag.text)

    一份年度报告可能包含多个<us-gaap:liabilities>元素,每个元素对应一个不同的报告期。每个时期对应一个<context>元素,因此您可以通过检查其contextRef属性来区分GAAP元素。

    3. 完整的EDGAR-XBRL示例

    如果你关注了上一篇文章和本文的内容,你应该不难理解如何在Python中访问一家公司的EDGAR报告并解析它们。为了证明这一点,清单1中的代码在EDGAR中搜索IBM(CIK:0000051143)的2014年年报(10-K),然后解析XBRL以确定股东权益(us-gaap:stockholdersequity)。

    清单1:从IBM的年报中读取股东权益(xbrl_reader.py)

from bs4 import BeautifulSoup
import requests
import sys

# Access page
cik = '0000051143'
type = '10-K'
dateb = '20160101'

# Obtain HTML for search page
base_url = "https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK={}&type={}&dateb={}"
edgar_resp = requests.get(base_url.format(cik, type, dateb))
edgar_str = edgar_resp.text

# Find the document link
doc_link = ''
soup = BeautifulSoup(edgar_str, 'html.parser')
table_tag = soup.find('table', class_='tableFile2')
rows = table_tag.find_all('tr')
for row in rows:
    cells = row.find_all('td')
    if len(cells) > 3:
        if '2015' in cells[3].text:
            doc_link = 'https://www.sec.gov' + cells[1].a['href']

# Exit if document link couldn't be found
if doc_link == '':
    print("Couldn't find the document link")
    sys.exit()

# Obtain HTML for document page
doc_resp = requests.get(doc_link)
doc_str = doc_resp.text

# Find the XBRL link
xbrl_link = ''
soup = BeautifulSoup(doc_str, 'html.parser')
table_tag = soup.find('table', class_='tableFile', summary='Data Files')
rows = table_tag.find_all('tr')
for row in rows:
    cells = row.find_all('td')
    if len(cells) > 3:
        if 'INS' in cells[3].text:
            xbrl_link = 'https://www.sec.gov' + cells[2].a['href']

# Obtain XBRL text from document
xbrl_resp = requests.get(xbrl_link)
xbrl_str = xbrl_resp.text

# Find and print stockholder's equity
soup = BeautifulSoup(xbrl_str, 'lxml')
tag_list = soup.find_all()
for tag in tag_list:
    if tag.name == 'us-gaap:stockholdersequity':
        print("Stockholder's equity: " + tag.text)

    只有当SEC不改变EDGAR网站的标记时,这段代码才能正常工作。当然,标记不可能随着时间的推移而保持不变,所以请记住,你可能需要挖掘标记来更新代码。更多Python教程尽在开课吧Python教程频道

有用
分享
全部评论快来秀出你的观点
登录 后可发表观点…
发表
暂无评论,快来抢沙发!
零基础轻松入门Python