【问题标题】:Switching from beautifulsoup to htmlelement - how to find elements从 beautifulsoup 切换到 htmlelement - 如何查找元素
【发布时间】:2020-04-16 10:29:12
【问题描述】:

我有一个现有的过程,可以从使用 xbrli xml 标准的 html 文档中提取元素。

并且可以找到文档示例here:

该过程运行良好(我正在使用多处理并行工作)但我有大约 20m html 和 xml 文件要处理,我发现 beautifulsoup 是核心瓶颈。

我将 htmlelement 视为提取所需数据的一种希望更快的替代方法,但我正在努力寻找元素。例如,在 BS 中,我可以执行以下操作:

for tag in soup.find_all('xbrli:unit'):

    l_unitid = tag.attrs.get('id')
    l_value = tag.text

    l_unit_dict[l_unitid] = {'unitid':l_unitid,'value':l_value}

这将找到所有 xbrli:unit 标签,我可以轻松提取它们的值。

但是,当我在 htmlelement 中尝试类似的操作时,会出现以下异常:

import htmlement

source = htmlement.parse("Prod223_2542_00010416_20190331.html")

for tag in source.iterfind('.//xbrli:unit'):

    l_unitid = tag.attrs.get('id')
    l_value = tag.text

    print(l_unitid)
    print(l_value)

    SyntaxError: prefix 'xbrli' not found in prefix map

我在谷歌上搜索了几篇文章,但我似乎无法取得进展 SyntaxError: prefix 'a' not found in prefix map

Parsing XML with namespace in Python via 'ElementTree'

我尝试在命名空间映射中添加,但无论我把东西放在哪个方向,或者我在寻找什么标签,它都没有找到任何东西

source = htmlement.parse("Prod223_2542_00010416_20190331.html")

namespaces = {'xbrli': 'period'}

for tag in source.iterfind('.//xbrli:period',namespaces):

    l_unitid = tag.attrs.get('id')
    l_value = tag.text

namespaces = {'xbrli': 'period'}

for tag in source.iterfind('.//{xbrli}period',namespaces):

    l_unitid = tag.attrs.get('id')
    l_value = tag.text

    print(l_unitid)
    print(l_value)

namespaces = {'period':'xbrli'}
for tag in source.iterfind('.//{xbrli}period',namespaces):

    l_unitid = tag.attrs.get('id')
    l_value = tag.text

    print(l_unitid)
    print(l_value)

namespaces = {'period':'xbrli'}

for tag in source.iterfind('.//period',namespaces):

    l_unitid = tag.attrs.get('id')
    l_value = tag.text

    print(l_unitid)
    print(l_value)

所有都没有返回 - 他们不进入循环。我对如何使用 elementree 结构与 BS 的理解显然有一些非常错误的地方,但我不太清楚如何从一个转移到另一个。

欢迎提出任何建议。

【问题讨论】:

  • 我有点困惑:你能编辑你的问题以显示你是如何获得source的吗?
  • @JackFleeting 抱歉,是的,我没有发现我错过了。现在就在里面

标签: xpath beautifulsoup elementtree


【解决方案1】:

在我得到建议的答案之前,有两个通用的 cmets: 首先,您正在处理一个 xml 文档,因此通常最好使用 xml 而不是 html 解析器。所以这就是我在下面使用的,而不是美丽的汤或 htmlelement。

第二,关于 xbrl 的总体情况:从痛苦的经历(以及许多其他人指出的)来看,xbrl 很糟糕。它在表面上很闪亮,但一旦你打开引擎盖,它就会变得一团糟。所以我不羡慕你……

而且,话虽如此,我试图估计您可能正在寻找的内容。我没有费心创建字典或列表,只是使用了print() 语句。显然,如果它对您有帮助,您可以根据自己的要求对其进行修改:

from lxml import etree
import requests
r = requests.get('https://beta.companieshouse.gov.uk/company/00010416/filing-history/MzI1MTU3MzQzMmFkaXF6a2N4/document?format=xhtml&download=1') 

root = etree.fromstring(r.content)
units = root.xpath(".//*[local-name()='unit'][@id]/@id")
for unit in units:
    unit_id = unit
    print('unit: ', unit)
print('----------------------------')

context = root.xpath(".//*[local-name()='context']")
for tag in context:
    id = tag.xpath('./@id')
    print('ID: ',id)
    info = tag.xpath('./*[local-name()="entity"]')
    identifier = info[0].xpath('.//*[local-name()="identifier"]')[0].text
    print('identifier: ',identifier)
    member = info[0].xpath('.//*[local-name()="explicitMember"]')
    if len(member)>0:
        dimension = member[0].attrib['dimension']
        explicitMember = member[0].text
        print('dimension: ',dimension,' explicit member: ',explicitMember)
    periods = tag.xpath('.//*[local-name()="period"]')
    for period in periods:
        for child in period.getchildren():
            if 'instant' in child.tag:
                instant = child.text
                print('instant: ',instant)
            else:
                dates = period.xpath('.//*')
                start_date = dates[0].text
                end_date = dates[1].text
        print('start date: ', start_date,' end date: ',end_date)

    print('===================')

来自输出的随机样本:

ID:  ['cfwd_31_03_2018']
identifier:  00010416
instant:  2018-03-31
start date:  2017-04-01  end date:  2018-03-31
===================
ID:  ['CountriesHypercube_FY_31_03_2019_Set1']
identifier:  00010416
dimension:  ns15:CountriesRegionsDimension  explicit member:  ns15:EnglandWales
instant:  2018-03-31
start date:  2018-04-01  end date:  2019-03-31

【讨论】:

  • 哇,这有什么不同。我已经以您的示例为例,并将其扩展为复制我已有的内容,并且这些数字令人印象深刻。我使用两种方法(BS4 80.09s、LXML 12.62s)对本地存储的 1000 个文档进行了快速基准测试。所以进步很大。谢谢 !还有 re xbrl - 是的,它让我的眼睛流血了!
猜你喜欢
  • 1970-01-01
  • 2021-12-27
  • 2017-03-08
  • 2021-10-24
  • 1970-01-01
  • 1970-01-01
  • 2018-12-08
  • 2020-09-28
  • 1970-01-01
相关资源
最近更新 更多