【问题标题】:web scraping with beautifulsoup hiding elements使用 beautifulsoup 隐藏元素进行网页抓取
【发布时间】:2018-11-04 19:03:53
【问题描述】:

我正在尝试使用BeautifulSoup 抓取以下网址: https://www.investopedia.com/markets/stocks/aapl/#Financials

我试图解析我用检查找到的这个部分:

     <div class="value">
          <div class="marker position" style="left: 89.25%;"></div>
          <div class="text position" style="left: 89.25%;">1.43</div>
     </div>

MyCode如下:

import bs4 as bs
import requests

def load_ticker_invest(ticker):
resp = requests.get('https://www.investopedia.com/markets/stocks/{}/#Financials'.format(ticker))
    soup = bs.BeautifulSoup(resp.text, 'html.parser')
    trend = soup.div.find_all('div', attrs={'class':'value'})

    return trend

print (load_ticker_invest('aapl'))

我得到的结果是一个空白列表:

[]

我该如何解决这个问题?

【问题讨论】:

  • 我现在无法检查(在我的手机上),但你确定这个 HTML 实际上是在 HTML 源代码中,还是从一些使用 Javascript 的 API 中提取的?如果是后者,那么您无法通过抓取获得它,而必须直接使用 API(这通常更容易,假设它们允许公共访问)。
  • 我刚刚在我的笔记本电脑上检查过——在查看源代码后搜索“marker-position”没有任何结果,即使像你一样我可以通过检查看到该 HTML。所以正如我所说,它必须在客户端动态生成。至少他们的一个缩小的 JS 文件中有一堆 Ajax 调用,不幸的是,其中很多都被混淆了,所以我还没有找到你正在追踪的特定数据来自哪里的 URL。
  • 它不在 HTML 源代码中并且认为它是从 API 中提取的,你能告诉我如何访问 API 吗?
  • 恐怕我不知道,这不是我使用过的网站,我对交易或投资一无所知 :) 我认为没有比挖掘网站的 javascript 代码更好的方法了并试图找出它是从哪个 URL 派生的——但这不是一件容易的事。

标签: python web-scraping beautifulsoup


【解决方案1】:

此站点使用内部 API 来获取这些数据,此 API 调用需要一些令牌,这些令牌嵌入在页面 https://www.investopedia.com/markets/stocks/aapl 内的某些 Javascript 脚本中,因此您需要首先使用一些正则表达式废弃这些值,然后在API调用

使用带有 的 bash 脚本:

title=aapl

IFS=' ' read token token_userid < <(curl -s "https://www.investopedia.com/markets/stocks/$title/" | \
     tr -d '\n' | \
     sed -rn "s:.*Xignite\(\s*'([A-Z0-9]+)',\s*'([A-Z0-9]+)'.*:\1 \2:p")

curl -s "https://factsetestimates.xignite.com/xFactSetEstimates.json/GetLatestRecommendationSummaries?IdentifierType=Symbol&Identifiers=$title&UpdatedSince=&_token=$token&_token_userid=$token_userid" | \
     jq -r '.[].RecommendationSummarySet | .[].RecommendationScore'

使用

import requests
import re

ticker = 'aapl'

r = requests.get('https://www.investopedia.com/markets/stocks/{}/'.format(ticker))

result = re.search(r".*Xignite\(\s*'([A-Z0-9]+)',\s*'([A-Z0-9]+)'", r.text)

token = result.group(1)
token_userid = result.group(2)

r = requests.get('https://factsetestimates.xignite.com/xFactSetEstimates.json/GetLatestRecommendationSummaries?IdentifierType=Symbol&Identifiers={}&UpdatedSince=&_token={}&_token_userid={}'
    .format(ticker, token, token_userid)
)

print(r.json()[0]['RecommendationSummarySet'][0]['RecommendationScore'])

【讨论】:

  • 是的,效果很好。 Selenium 也可以,但是您的代码似乎要好得多。
  • @KeyvanTajbakhsh 我认为在这种情况下你应该坚持使用 selenium 解决方案,因为上面的解决方案使用正则表达式,如果在这个网站上进行小升级,它会很快崩溃
【解决方案2】:
import requests
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
import bs4 as bs

caps = DesiredCapabilities().CHROME
caps["pageLoadStrategy"] = "normal"
driver = webdriver.Chrome(desired_capabilities=caps)
driver.get('https://www.investopedia.com/markets/stocks/aapl/#Financials')
resp = driver.execute_script('return document.documentElement.outerHTML')
driver.quit()

soup = bs.BeautifulSoup(resp, 'html.parser')
res = soup.find('div', attrs={'class':'text position'}).text
print (res)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-05
    • 2018-08-02
    • 1970-01-01
    • 2020-10-04
    • 2021-01-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多