【问题标题】:BeautifulSoup - Finding children based on location of other child's parentBeautifulSoup - 根据其他孩子父母的位置寻找孩子
【发布时间】:2019-06-16 02:14:57
【问题描述】:

我想使用 python、beautifulsoup 等查找特定日期的数据。有问题的日期 IMPORTANT DATEMar. 31, 2018,如下所示。

<tr class="ro">
<td class="pl " style="border-bottom: 0px;" valign="top"><a class="a" href="javascript:void(0);" onclick="top.Show.showAR( this, 'defref_dei_DocumentPeriodEndDate', window );">IMPORTANT DATE</a></td>
<td class="text">Mar. 31,  2018<span></span>
</td>
<td class="text">&#160;<span></span>
</td>
</tr>

我正在使用以下代码行来识别IMPORTANT DATE

for item in soup.find('td', text='Document Period End Date').parent.find_all('td', {'class':['text']}):
    if len(item.text.strip()) > 0:
        report_date = [item.text.strip()]
        print(report_date)

注意if len(item...) 的使用。这是摆脱&amp;#160 的一种骇人听闻的方式,但它确实有效。任何更好的建议都值得赞赏,但不是我问题的主要焦点......继续前进。

我的主要问题是,如果我们确定IMPORTANT DATE 孩子的位置是#1(见下文),那么我们如何才能继续获取某些元素的第一个孩子(同一个祖父母)?见下文。

<tr>
<th class="tl" colspan="1" rowspan="1"><div style="width: 200px;"><strong>Condensed Consolidated Balance Sheets - USD ($)<br> $ in Thousands</strong></div></th>
<th class="th"><div>Mar. 31, 2018</div></th> # <-IMPORTANT DATE, 1st 
<th class="th"><div>Dec. 31, 2017</div></th> # <-wrong date 
</tr>
<tr class="ro">
<td class="pl " style="border-bottom: 0px;" valign="top"><a class="a" href="javascript:void(0);" onclick="top.Show.showAR( this, 'defref_us-gaap_InventoryNet', window );">Inventories, net</a></td>
<td class="nump">76,579<span></span> # <- data for important date 
</td>
<td class="nump">92,376<span></span> # <- data from wrong date
</td>
</tr>

为了抛出一个曲线球,有时重要数据的位置不是IMPORTANT DATE 的位置,因为我假设它们的父&lt;tr&gt; 元素下的一些标题列。见下文。

<tr>
<th class="th" colspan="1">3 Months Ended</th>
<th class="th" colspan="1"></th>
</tr>
<tr>
<th class="th"><div>Mar. 31, 2018</div></th> #<- IMPORTANT DATE, 3rd
<th class="th"><div>Dec. 31, 2017</div></th>
<tr class="ro">
<td class="pl " style="border-bottom: 0px;" valign="top"><a class="a" href="javascript:void(0);" onclick="top.Show.showAR( this, 'defref_us-gaap_LongTermDebt', window );">Long-term debt</a></td>
<td class="nump">data for important date<span></span> #<- important data is 1st
</td>
<td class="nump">unimportant data<span></span>
</td>

我计划做的是 1)在 python 中创建对 IMPORTANT DATE 的引用,report_date 与它 2)将我们的重要数据的日期与我们的 IMPORTANT DATE 进行比较,最后 3)返回重要数据。但是,在 1) 和 2) 之间的某个地方,我的代码出现故障是因为在尝试以下几行时:

for item in soup.select('filename:contains("' + filename + '")'):
    for item in soup.find('td', text='Document Period End Date').parent.find_all('td', {'class':['text']}):
        if len(item.text.strip()) > 0:
            report_date = [item.text.strip()]
    for th in item.find_all('th', text=report_date):

我知道在某些时候css_selector soup.select("p &gt; a:nth-of-type(2)") 会派上用场,但我还没有到那一步;我似乎被卡住了。

这里有人可以帮忙吗?

soup can be found here

【问题讨论】:

  • IMPORTANT DATE 总是出现在 HTML sn-ps 中的第一个日期吗?似乎在上面的所有示例中,您想要的日期可能在 HTML 中稍后出现的任何其他日期之前。
  • 不一定。重要日期是从汤的另一行代码中找到的。从那里我想用那个日期作为参考。
  • 似乎,在上面的小例子中,所需的数据总是类名 num 上的第一个表匹配。所以,select_one('.nump').text 最好在类前面有一个表格 css 选择器,以确保你有正确的表格,例如#tableId .nump

标签: python python-3.x beautifulsoup css-selectors parent-child


【解决方案1】:

您可以通过执行 tr.select('td, th')[-2:] 从行 (&lt;tr&gt;) 中获取最后两个元素(&lt;td&gt;&lt;th&gt;)。这样,您将始终忽略该可选的第一个标题列。然后你可以做zip()函数来连接数据:

from bs4 import BeautifulSoup

case_1 = '''<table><tr>
<th class="th" colspan="1">3 Months Ended</th>
<th class="th" colspan="1"></th>
</tr>
<tr>
<th class="th"><div>Mar. 31, 2018</div></th>
<th class="th"><div>Dec. 31, 2017</div></th>
<tr class="ro">
<td class="pl " style="border-bottom: 0px;" valign="top"><a class="a" href="javascript:void(0);" onclick="top.Show.showAR( this, 'defref_us-gaap_LongTermDebt', window );">Long-term debt</a></td>
<td class="nump">data for important date<span></span> #<- important data is 1st
</td>
<td class="nump">unimportant data<span></span>
</td>
'''

case_2 = '''
<table>
<tr>
<th class="tl" colspan="1" rowspan="1"><div style="width: 200px;"><strong>Condensed Consolidated Balance Sheets - USD ($)<br> $ in Thousands</strong></div></th>
<th class="th"><div>Mar. 31, 2018</div></th>
<th class="th"><div>Dec. 31, 2017</div></th>
</tr>
<tr class="ro">
<td class="pl " style="border-bottom: 0px;" valign="top"><a class="a" href="javascript:void(0);" onclick="top.Show.showAR( this, 'defref_us-gaap_InventoryNet', window );">Inventories, net</a></td>
<td class="nump">76,579<span></span>
</td>
<td class="nump">92,376<span></span>
</td>
</tr>'''

soup1 = BeautifulSoup(case_1, 'lxml')
soup2 = BeautifulSoup(case_2, 'lxml')

def get_data(soup):
    return [[row_data.text.strip() for row_data in tr.select('td, th')[-2:]] for tr in soup.select('tr')[-2:]]

print('Case 1:')
for i, (date, data_for_date) in enumerate(zip(*get_data(soup1)), 1):
    print('{}.\t{} - {}'.format(i, date, data_for_date))

print('\nCase 2:')
for i, (date, data_for_date) in enumerate(zip(*get_data(soup2)), 1):
    print('{}.\t{} - {}'.format(i, date, data_for_date))

打印:

Case 1:
1.  Mar. 31, 2018 - data for important date #
2.  Dec. 31, 2017 - unimportant data

Case 2:
1.  Mar. 31, 2018 - 76,579
2.  Dec. 31, 2017 - 92,376

【讨论】:

  • 如果所需的数据位于第 3 行或第 4 行等,对于需要解析的不同汤,此方法可能没有那么有用。方法需要足够广泛,以适用于不同的汤。
猜你喜欢
  • 2017-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-26
  • 2016-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多