首页 > 解决方案 > 使用 BeautifulSoup 解析内容

问题描述

我正在尝试编写一个脚本,该脚本将采用 CIK、报告类型和可选的截至日期,并从 SEC EDGAR 公共索引返回解析的财务报告信息。

该脚本主要工作并返回所有值的数据框,其中包含从 contextref 属性解析的描述和参考年份。不幸的是,对于不同的标签,contextref 的形式存在相当多的可变性,所以我想知道是否有一种比我目前使用一些逻辑和正则表达式更简洁的方法来提取这些信息。我检查了 xbrl 文档,它引用了一个“句点”元素,但是当我检查tag.attrs. 想知道除了一些不稳定的正则表达式之外,是否有更直接的方法来提取这些信息。

如果它具有指导意义,很高兴提供更有问题的 contextref 值的示例。

以下代码的相关部分:

import pandas as pd
from bs4 import BeautifulSoup
from requests import get

link = 'https://www.sec.gov/Archives/edgar/data/789019/000156459018019062/msft-20180630.xml'
r = get(link)
str = r.text

soup = BeautifulSoup(str, 'lxml')
tags = soup.find_all()
df = pd.DataFrame(columns=['field','period','value']) 

for tag in tags:
    if ('us-gaap:' in tag.name   # only want gaap-related tags 
            and tag.text.isdigit()): # only want values, no commentary
        #a = re.match("^C_"+ re.escape(cik) + "_[0-9]", tag['contextref'])     
            name = tag.name.split('gaap:')[1]
            cref = tag['contextref'][-8:-4]
            value = tag.text
            df = df.append({'field': name, 'period': cref, 'value': value}, ignore_index=True)

print(df)

标签: pythonbeautifulsoupxbrl

解决方案


恐怕您的方法存在根本缺陷。contextRef 属性的值是一个任意标识符,它引用文档中其他地方的上下文元素。虽然您正在查看的示例中可能包含年份,但这些标识符可以是任何东西(例如 c1、c2、c3 等)。为了获得年份,您需要取消引用 contextRef 属性标识的上下文,并查看元素内的<period>元素,例如

<xbrli:context id="c1">
  <xbrli:entity>
       <xbrli:identifier scheme="http://www.example.com/1234">1234</xbrli:identifier>

  </xbrli:entity>
  <xbrli:period>
     <xbrli:startDate>2018-01-01</xbrli:startDate>
     <xbrli:endDate>2018-12-31</xbrli:endDate>
  </xbrli:period>
</xbrl:context>

此外,us-gaap:元素名称的一部分是名称空间前缀。XML 文档可以合法地使用其他前缀来引用相同的名称空间。重要的是前缀通过xmlns:us-gaap="..."声明绑定到的命名空间,通常在根元素上。您应该使用可识别名称空间的 XML 解析器。我认为 beautifulsoup 不能正确识别名称空间。

我相信 SEC 系统确实限制文件管理器使用“推荐的”命名空间前缀,因此您可能会在 SEC 文档上使用这种方法,但我强烈建议使用 XBRL 处理器来处理命名空间、取消引用上下文和许多其他问题与使用 XBRL 相关的问题。 Arelle是一个开源 XBRL 处理器,但还有许多其他可用的。

使用 XBRL 处理器还可以让您访问分类中的人类可读标签等信息。


推荐阅读