【问题标题】:Scraping infinite scrolling yahoo finance historical data刮取无限滚动雅虎财经历史数据
【发布时间】:2021-06-03 23:48:01
【问题描述】:

我正在尝试抓取过去 5 年 yahoo Finance 特定股票的历史数据。我已经实现了一个 Python 代码,该代码 scraping 包含历史数据的表的每一行。我知道有更简单的方法来获取历史数据,但我想用 scraping 来做到这一点。问题是雅虎财务已经在其中实现了无限滚动,即一旦我到达网站的末尾,就会有更多的行被动态添加到表格中。但是我的代码只获取到第一页末尾的行,而不是完整的 5 年数据。这是我正在尝试的代码示例:

scraping部分导航到行之后-

tableRows = table.find_all('tr', class_='BdT Bdc($seperatorColor) Ta(end) Fz(s) Whs(nw)')

我正在进一步从这些行中提取值

【问题讨论】:

标签: python ajax selenium web-scraping beautifulsoup


【解决方案1】:

您需要在浏览器中模仿用户行为才能获取其余结果。

  1. 您可以使用Selenium web driver
  2. 导航到页面末尾,除非没有更多结果显示(此步骤需要 Javascript,example)。在此步骤中,请确保您等待 AJAX 请求完成,否则您可能会遇到意外行为。
  3. 一旦不再显示结果,请使用您已在使用的选择器检索信息

【讨论】:

  • Hii.. 你的意思是我应该在运行我的代码以获取信息之前添加 JavascriptExecutor 的代码。正确的?能否请您指定 JavaScriptExecutor 的导入内容?
  • 即使我手动向下滚动到页面然后复制 url 并应用我的代码,它仍然只获取第一页条目的结果
  • @SiddharthBhatheja 如果在那之前没有其他人这样做,我将能够在大约 5-6 小时内提供一个工作示例。另外我更新了第二步中没有使用JavascriptExecutor的链接,请看一下。
【解决方案2】:

我建议你试试 yfinance 库 (https://pypi.org/project/yfinance/)

import yfinance as yf

msft = yf.Ticker("MSFT")

# get stock info
msft.info

# get historical market data
hist = msft.history(period="max")

【讨论】:

  • 我对这个答案投了赞成票。这绝对是做这种事情最有效的方法。
【解决方案3】:

Selenium 是一种方法。更高效的方式是直接查询数据:

import requests
import pandas as pd
import datetime

years = 5

dt= datetime.datetime.now()
past_date = datetime.datetime(year=dt.year-years, month=dt.month, day=dt.day)

url = 'https://query2.finance.yahoo.com/v8/finance/chart/RELIANCE.NS'
headers= {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36'}
payload = {
'formatted': 'true',
'crumb': 'J2oUJNHQwXU',
'lang': 'en-GB',
'region': 'GB',
'includeAdjustedClose': 'true',
'interval': '1d',
'period1': '%s' %int(past_date.timestamp()),
'period2': '%s' %int(dt.timestamp()),
'events': 'div|split',
'useYfid': 'true',
'corsDomain': 'uk.finance.yahoo.com'}



jsonData = requests.get(url, headers=headers, params=payload).json()
result = jsonData['chart']['result'][0]

indicators = result['indicators']
rows = {'timestamp':result['timestamp']}
rows.update(indicators['adjclose'][0])
rows.update(indicators['quote'][0])

df = pd.DataFrame(rows)
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='s')

输出:

print(df)
               timestamp     adjclose  ...         open          low
0    2016-03-08 03:45:00   492.139252  ...   499.019806   499.019806
1    2016-03-09 03:45:00   499.183502  ...   505.211090   504.517670
2    2016-03-10 03:45:00   484.831451  ...   516.132568   499.762756
3    2016-03-11 03:45:00   486.149292  ...   502.685059   500.555237
4    2016-03-14 03:45:00   488.665009  ...   504.765320   501.719208
                 ...          ...  ...          ...          ...
1229 2021-03-01 03:45:00  2101.699951  ...  2110.199951  2062.500000
1230 2021-03-02 03:45:00  2106.000000  ...  2122.000000  2089.100098
1231 2021-03-03 03:45:00  2202.100098  ...  2121.050049  2107.199951
1232 2021-03-04 03:45:00  2175.850098  ...  2180.000000  2157.699951
1233 2021-03-05 09:59:59  2178.699951  ...  2156.000000  2153.050049

[1234 rows x 7 columns]

【讨论】:

  • 嗨.. 这似乎是一个很好的解决方案。我试试看。太感谢了。只是为了知识,因为我是数据科学的新手,我采用的方法是否不可能,即按类查找 html 元素表(例如,首先按类查找表,然后查找该表的所有行通过他们的班级,然后像我一样使用 for 循环以编程方式从这些行中提取信息?)。请告诉我
  • 这仍然是绝对可能的。只是一种不同的方式去解决它。以这种方式解析 html 的唯一问题是您 a) 仅限于 html 中的数据,并且 b) 受 html 结构的限制(意味着无论出于何种原因,如果主机更改了 html/网站,它可能会导致代码错误)。如果可以选择通过 api 或 <script> 标签获取数据,那通常会更强大,因为它几乎总是是 json 格式。而且通常会有更多的元数据。但用 selenium 或 beautifulsoup 做这件事并没有错
  • 所以澄清一下,这通常是我尝试抓取的顺序。 1)检查api; 2) 检查脚本标签中是否有数据; 3a) 如果是 标签,使用 pandas .read_html; 3b) 如果不是
    标签(或需要额外的数据,例如
    中的 标签中的 href),则使用 bs4 按标签解析数据; 4)使用selenium渲染页面,然后使用pandas/bs4解析数据; 5) 查看是否可以在不同的网站上找到相同的数据。
【解决方案4】:

已经展示了很多更好的解决方案,但我只是向您展示如何通过按“END”键来完成

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys

driver = webdriver.Chrome()
driver.implicitly_wait(6)


driver.get("https://uk.finance.yahoo.com/quote/RELIANCE.NS/history?period1=1297987200&period2=1613606400&interval=1d&filter=history&frequency=1d&includeAdjustedClose=true")

driver.find_element_by_xpath('//*[@id="consent-page"]/div/div/div/form/div[2]/div[2]/button').click()

history_table = driver.find_element_by_xpath('//*[@id="Col1-1-HistoricalDataTable-Proxy"]/section/div[2]/table/tbody').find_elements_by_tag_name("tr")
# while year >= 2020 - 5
while(int(history_table[-1].find_elements_by_tag_name("td")[0].text.split()[2]) >= 2020-5):
    history_table = driver.find_element_by_xpath(
        '//*[@id="Col1-1-HistoricalDataTable-Proxy"]/section/div[2]/table/tbody').find_elements_by_tag_name("tr")
    action = ActionChains(driver)
    action.send_keys(Keys.END).perform()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 2018-04-21
    • 1970-01-01
    • 2015-05-07
    • 1970-01-01
    • 1970-01-01
    • 2022-12-05
    相关资源
    最近更新 更多