如何从不同的表条目中提取信息:Text vs. DIV vs. SPAN

Posted

技术标签:

【中文标题】如何从不同的表条目中提取信息:Text vs. DIV vs. SPAN【英文标题】:How to extract info from varying table entries: Text vs. DIV vs. SPAN 【发布时间】:2015-06-18 14:43:21 【问题描述】:

我是 python 新手,在网上搜索了我的问题的答案,但到目前为止我失败了......

问题:我的目标是从网站中提取数据。更具体地说,来自这些网站中的表格。您在我的 python 代码示例中的“data”中找到的网站代码中的相关 sn-p:

from bs4 import BeautifulSoup

data = '''<table class="ds-table">
        <tr>
          <td class="data-label">year of birth:</td>
                        <td class="data-value">1994</td>
       </tr>
        <tr>
            <td class="data-label">reporting period:</td>
          <td class="data-value">
            <span class="editable" id="c-scope_beginning_date">
              ?                </span>
            &nbsp;-&nbsp;
            <span  class="editable" id="c-scope_ending_date">
              ?                </span>
          </td>
         </tr>
        <tr>
            <td class="data-label">reporting cycle:</td>
          <td class="data-value">
            <span class="editable" id="c-periodicity">
              -                </span>
          </td>
        </tr>
        <tr>
              <td class="data-label">grade:</td>
              <td class="data-value">1.3, upper 10% of class</td>
            </tr>
            <tr>
              <td class="data-label">status:</td>
              <td class="data-value"></td>
              </tr>
      </table>
        <table class="ds-table">
             <tr>
              <td class="data-label">economics:</td>
                <td class="data-value"><span class="positive-value"></span></td>
            </tr>
             <tr>
              <td class="data-label">statistics:</td>
              <td class="data-value"><span class="negative-value"></span></td>
            </tr>
            <tr>
          <td class="data-label">social:</td>
          <td class="data-value"><div id="music_id" class="trigger"><span class="negative-value"></span></div></td>
        </tr>
        <tr>
          <td class="data-label">misc:</td>
           <td class="data-value">
            <div id="c_assurance" class="">
                <span class="positive-value"></span>                </div>
           </td>
        </tr>
        <tr>
            <td class="data-label">recommendation:</td>
            <td class="data-value">
                <span class="negative-value"></span>                </td>
        </tr>  
                  </table>'''

soup = BeautifulSoup(data)

对于class="data-label"到目前为止我成功实现了...

box_cdl = []
for i, cdl in enumerate(soup.findAll('td', attrs='class': 'data-label')):
    box_cdl.append(cdl.contents[0])
print box_cdl

...从列中提取文本,在(对我来说令人满意的)输出中:

[u'year of birth:',
 u'reporting period:',
 u'reporting cycle:',
 u'grade:',
 u'status:',
 u'economics:',
 u'statistics:',
 u'social:',
 u'misc:',
 u'recommendation:']

我卡住的地方是 class="data-value" 的部分,带有 div- 和 span- 字段,并且一些相关信息隐藏在 跨度类。此外,tr-rows 的数量可能会因网站而异,例如“状态”出现在“报告周期”之后(而不是“等级”)。

但是,当我这样做时......

box_cdv = []
for j, cdv in enumerate(soup.findAll('td', attrs='class': 'data-value')):
   box_cdv.append(cdv.contents[0])
print box_cdv

...我收到错误:

Traceback (most recent call last):

  File "<ipython-input-53-7d5c095cf647>", line 3, in <module>
    box_cdv.append(cdv.contents[0])

IndexError: list index out of range

我想得到的是这样的东西(对应于上面的“data”-example):

[u'1994',
 u'? &nbsp;-&nbsp; ?',
 u'-',
 u'1.3, upper 10% of class',
 u'',
 u'positive-value',
 u'negative-value',
 u'negative-value',
 u'positive-value',
 u'negative-value']

问题:鉴于适当的提取代码取决于类别(出生年份、报告期、...、推荐)?

或者,问不同:什么代码提取我,取决于类别(出生年份,报告期,...,推荐),相应的值(1994,...,负-值)?

由于不同网站的表格条目的数量和类型可能不同,简单的“在第 i 个条目上执行以下操作”程序不适用。我想我正在寻找的东西类似于“如果你找到文本“推荐:”,然后从跨度字段中提取类类型”,我猜。但不幸的是,我不知道如何将其翻译成 python 语言。

非常感谢任何帮助。

【问题讨论】:

【参考方案1】:

您收到该错误是因为其中一个标签没有任何children,因此contents 列表在搜索该索引时会出错。

您可以通过以下方式解决此问题:

1) 搜索data-label标签;

2) 找到下一个TD 兄弟;

3 A) 检查同级是否有文本;

3 A) 1) 如果是这样,则创建一个以data-label 为键、兄弟文本为其值的字典条目;

3 A) B) 如果没有,则检查同级第一个孩子是否有一个包含-value`的类

4) 解析数据。

例子:

soup = BeautifulSoup(data, 'lxml')

result = 

for tag in soup.find_all("td",  "class" : "data-label" ):
    NextSibling = tag.find_next("td",  "class" : "data-value" ).get_text(strip = True)
    if not NextSibling and len(tag.find_next("td").select('span[class*=-value]')) > 0:
        NextSibling = tag.find_next("td").select('span[class*=-value]')[0]["class"][0]
    result[tag.get_text(strip = True)] = NextSibling

print (result)

结果:

'出生年份:': '1994', '报告期:': '?-?', '报告周期:':'-', 'grade:': '1.3, 班级前 10%', '状态:': '', '经济学:':'正值', '统计:':'负值', '社会:':'负值', 'misc:': '正值', '推荐:':'负值'

【讨论】:

以上是关于如何从不同的表条目中提取信息:Text vs. DIV vs. SPAN的主要内容,如果未能解决你的问题,请参考以下文章

从数据库中提取单独的表

如何从 SQLite 中的表中选择最新的 100 个不同条目?

Logstash RSS Feed(重复数据删除并提取某些数据)

如何根据多个by-record标准从data.table中提取特定字段?

条件JOIN不同的表

休眠。如何将条目添加到具有来自 Hibernate 中 2 个不同表的 2 个外键的表中?