【问题标题】:Why is this tag empty when parsed with beautiful soup?为什么用美汤解析这个标签是空的?
【发布时间】:2014-12-06 03:32:47
【问题描述】:

我正在用漂亮的汤来解析这个页面:

https://au.finance.yahoo.com/q/is?s=AAPL

我正在尝试获取 27/09/2014 (42,123,000) 的总收入,这是靠近顶部的声明中的第一个值。

我在 chrome 工具中检查了该元素,发现该值在一个类名为 yfnc_tabledata1 的表中。

我的python代码如下:

import requests
import bs4

#get webpage
page = requests.get("https://au.finance.yahoo.com/q/is?s=AAPL")

#put into beautiful soup
soup = bs4.BeautifulSoup(page.content)

#select tag
tag = soup.select("table.yfnc_tabledata1")

到目前为止一切顺利,这会抓取包含所需数据的表,但这是我卡住的地方。

通向我想要的数据的链条如下:

tag > tbody > tr > td > table > tbody > (then the second tr)

但是当我尝试使用它时,我得到一个空元素。

谁能帮我解决这个问题?

还有加分,谁能告诉我如何在更一般的意义上学习提取这样的数据?我经常需要提取隐藏在 HTML 文档中的数据,而且似乎永远无法计算出正确的代码来获取我想要的数据。

非常感谢任何帮助。

【问题讨论】:

    标签: python html beautifulsoup html-parsing


    【解决方案1】:

    HTML 中没有<tbody> 标签。

    如果您使用浏览器(例如,使用 Chrome 开发人员工具)查看页面,看起来有一个 <tbody> 标签,但这是 Chrome 插入到 DOM 中的虚假标签。

    尝试在搜索链中省略这两个标签。我确定第一个不存在并且(尽管 HTML 很难阅读)我很确定第二个也不存在。

    更新:这里是以您感兴趣的表格开头的 HTML:

    <TABLE class="yfnc_tabledata1" width="100%" cellpadding="0" cellspacing="0" border="0">
      <TR>
        <TD>
          <TABLE width="100%" cellpadding="2" ...>
            <TR class="yfnc_modtitle1" style="border-top:none;">
              <td colspan="2" style="border-top:2px solid #000;">
                <small><span class="yfi-module-title">Period Ending</span></small>
              </td>
              <th scope="col" style="border-top:2px ...">27/09/2014</th>
              <th scope="col" style="border-top:2px ...">28/06/2014</th>
              ...
    

    所以没有&lt;tbody&gt; 标签。

    【讨论】:

    • 哦,你怎么知道是假标签?
    • 该死,为什么 chrome 开发工具会这样做?它真的把我搞砸了。
    • 为了统一,Chrome 在 DOM 中创建了一个 tbody 元素,即使在 HTML 中没有指定一个元素。您在 Chrome 开发工具中看到的是在内存中创建的。这只是你从经验中学到的东西。
    • 这就是为什么我总是倾向于首先在 shell 上使用curl 获取,以便查看服务器真正返回的内容......
    【解决方案2】:

    让我们具体实用

    想法是找到Total Revenue标签并使用.next_sibling获取下一个单元格的文本:

    table = soup.find("table", class_="yfnc_tabledata1")
    total_revenue_label = table.find(text=re.compile(r'Total Revenue'))
    print total_revenue_label.parent.parent.next_sibling.get_text(strip=True)
    

    演示:

    >>> import re
    >>> import requests
    >>> import bs4
    >>> 
    >>> page = requests.get("https://au.finance.yahoo.com/q/is?s=AAPL")
    >>> soup = bs4.BeautifulSoup(page.content)
    >>> 
    >>> table = soup.find("table", class_="yfnc_tabledata1")
    >>> total_revenue_label = table.find(text=re.compile(r'Total Revenue'))
    >>> total_revenue_label.parent.parent.next_sibling.get_text(strip=True)
    42,123,000
    

    【讨论】:

    • 有没有一种简单的方法可以将该数字跳到下一个数字,即我可以通过print rev.parent.parent.next_sibling.next_sibling.get_text(strip=True) 做到这一点,但这似乎很荒谬。获取上一季度数据(37,432,000)
    • @Kane 是的,使用find_next_siblings() 方法。
    • @Kane 换句话说,result = [item.get_text(strip=True) for item in total_revenue_label.parent.parent.find_next_siblings()]
    【解决方案3】:

    回答您的一般问题:

    我推荐《挖掘社交网络》第二版。特别是第 5 章 - “挖掘网页”。

    本书的源代码可在here on github获取。

    【讨论】:

      【解决方案4】:

      认为可能有更好的方法来获取您想要的数据? 许多机构多年来一直免费提供它,例如。你想要的信息在哪里?

      http://www.afr.com/share_tables/

      【讨论】:

      • 感谢您为它添加了书签。不幸的是,它似乎只涵盖了在澳交所上市的股票。
      • 我相信其他证券交易所也有类似的数据源。 (我不知道新西兰等)。
      • nasdaqomx.com/transactions/marketdata/datafeedseoddata.com 等等。(我不知道它们是否免费或有什么好处)。 ymmv。有很多。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-18
      • 1970-01-01
      • 2011-04-20
      • 1970-01-01
      • 2014-08-11
      • 2013-04-29
      相关资源
      最近更新 更多