雅虎财经 V7 API 现在需要 cookie? (Python)

问题描述 投票:0回答:7
url = 'https://query2.finance.yahoo.com/v7/finance/quote?symbols=TSLA&fields=regularMarketPreviousClose&region=US&lang=en-US'
headers = {
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36'
}
data = requests.get(url,headers=headers)
prepost_data = data.json()

最近,雅虎财经更改了他们的 V7 API,要求每个请求都使用 cookie。运行上面的代码,我收到 Invalid Crumb 错误

{"finance":{"result":null,"error":{"code":"Unauthorized","description":"Invalid Crumb"}}}

此 Github 存储库中似乎也已知此问题:https://github.com/joshuaulrich/quantmod/issues/382

他们似乎有一个有效的补丁:https://github.com/joshuaulrich/quantmod/pull/383/commits

但是代码都是用 R 编写的...有人知道如何将其翻译成 Python 吗?

python cookies python-requests yahoo-finance
7个回答
9
投票

这对我有用。

  1. 对 URL https://fc.yahoo.com 进行 HTTP GET 调用。虽然此调用会导致 404 错误,但我们只需要它从响应标头中提取
    set-cookie
    ,然后在后续调用中使用
  2. 现在,通过包含从之前的响应标头中获取的 cookie,对 URL https://query2.finance.yahoo.com/v1/test/getcrumb 进行 HTTP GET 调用。此调用将检索碎屑值。
  3. 替换以下 URL 中的
    [crumb-value]
    并使用 cookie 进行 HTTP GET 调用 https://query2.finance.yahoo.com/v7/finance/quote?symbols=TSLA&crumb=[crumb-value]
  4. 缓存 cookie 值和 crumb 值以跳过前两个步骤

3
投票

这是一个基于 @mahindar 的答案的示例 Python 代码,用于获取 cookie 和 crumb:

import requests


def get_yahoo_cookie():
    cookie = None

    user_agent_key = "User-Agent"
    user_agent_value = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"

    headers = {user_agent_key: user_agent_value}
    response = requests.get(
        "https://fc.yahoo.com", headers=headers, allow_redirects=True
    )

    if not response.cookies:
        raise Exception("Failed to obtain Yahoo auth cookie.")

    cookie = list(response.cookies)[0]

    return cookie


def get_yahoo_crumb(cookie):
    crumb = None

    user_agent_key = "User-Agent"
    user_agent_value = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"

    headers = {user_agent_key: user_agent_value}

    crumb_response = requests.get(
        "https://query1.finance.yahoo.com/v1/test/getcrumb",
        headers=headers,
        cookies={cookie.name: cookie.value},
        allow_redirects=True,
    )
    crumb = crumb_response.text

    if crumb is None:
        raise Exception("Failed to retrieve Yahoo crumb.")

    return crumb


# Usage
cookie = get_yahoo_cookie()
crumb = get_yahoo_crumb(cookie)

2
投票

为了完成,让我添加一个 JavaScript 版本。我对这个问题进行了相当多的研究,令我惊讶的是最终的解决方案是如此简单。 或者,也可以从 Finance.yahoo.com 获取并提取 cookie 和 crumb

const API = 'https://query2.finance.yahoo.com'

async function getCredentials() {
  // get the A3 cookie
  const { headers } = await fetch('https://fc.yahoo.com')
  const cookie = headers.get('set-cookie')
  // now get the crumb
  const url = new URL('/v1/test/getcrumb', API)
  const request = new Request(url)
  request.headers.set('cookie', cookie)
  const response = await fetch(request)
  const crumb = await response.text()
  return { cookie, crumb } 
}

async function quote(symbols, cookie, crumb) {
  const url = new URL('v7/finance/quote', API)
  url.searchParams.set('symbols', symbols.join(','))
  url.searchParams.set('crumb', crumb)
  const request = new Request(url)
  request.headers.set('cookie', cookie)
  const response = await fetch(request)
  const {quoteResponse} = await response.json()
  return quoteResponse?.result || []
}

// main
const { cookie, crumb } = await getCredentials()
const quotes = await quote(['GOOG', 'TSLA'], cookie, crumb)
if (quotes.length) {
  for (const quote of quotes) {
    console.log(`${quote.symbol} price is ${quote.currency} ${quote.regularMarketPrice}`)
  }
}

1
投票

我是用php做的,代码是:


<?php

/* 1 - Get cookie */
//https://stackoverflow.com/questions/76065035/yahoo-finance-v7-api-now-requiring-cookies-python
$url_yahoo = "https://fc.yahoo.com";
$yahoo_headers = get_headers($url_yahoo, true);
//print_r($yahoo_headers);
$cookie_name = 'Set-Cookie';

/* 2 - Get crumb , setting cookie */
$url_yahoo2 = "https://query2.finance.yahoo.com/v1/test/getcrumb";
$c = curl_init($url_yahoo2);
curl_setopt($c, CURLOPT_VERBOSE, 1);
curl_setopt($c, CURLOPT_COOKIE, $yahoo_headers[$cookie_name]);
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
$crumb = curl_exec($c);
curl_close($c);
//echo "<BR>Crumb:" . $crumb;

/* 3 - Get quotes with crumb, setting cookie. Using sample tickets*/
$tickets_list = "AAPL,TSLA";
$url_cotacao = "https://query2.finance.yahoo.com/v7/finance/quote?symbols=" . $tickets_list . "&crumb=" . $crumb;
$c = curl_init($url_cotacao);
curl_setopt($c, CURLOPT_VERBOSE, 1);
curl_setopt($c, CURLOPT_COOKIE, $yahoo_headers[$cookie_name]);
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
$data_quote = curl_exec($c);
curl_close($c);


/* 4 - Get data from yahoo */
$resJson_decode = json_decode($data_quote, false);
if (!$resJson_decode->quoteResponse->result) {
    $resultado = "Ticket dont exists in yahoo!";
} else {
    foreach ($resJson_decode->quoteResponse->result as $ticket_result){
        echo "<BR>Ticket:" . $ticket_result->symbol;
        echo "<BR>Price:" . $ticket_result->regularMarketPrice;
    }
    
}


1
投票

PowerShell 使用示例:

    # ► Create $session Object
$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession
$Stock = "MSFT" 

    # ► Call 1st Url ( Gain some headers and cookies stuff ) - using try & catch to prevent 404 error ( as mentioned above )
try { Invoke-WebRequest -UseBasicParsing -Uri "https://fc.yahoo.com/" -SessionVariable session } catch {
  $null}        
        

    # ► Call 2nd Url ( Generate Crumb ) 
$crumb = Invoke-WebRequest -UseBasicParsing -Uri "https://query2.finance.yahoo.com/v1/test/getcrumb" -WebSession $session


    # ► Call 3rd Url ( Get Yahoo's Data ) 
$URL = $("https://query2.finance.yahoo.com/v10/finance/quoteSummary/" + $Stock + "?modules=price&crumb=" + $crumb)
$ResponseText = Invoke-WebRequest -UseBasicParsing -Uri $URL -WebSession $session

    
    # ► Print Result
$ResponseText = $ResponseText.ToString()
$ResponseText 

0
投票
import requests

apiBase = 'https://query2.finance.yahoo.com'
headers = { 
  "User-Agent": 
  "Mozilla/5.0 (Windows NT 6.1; Win64; x64)"
}

def getCredentials(cookieUrl='https://fc.yahoo.com', crumbUrl=apiBase+'/v1/test/getcrumb'):
  cookie = requests.get(cookieUrl).cookies
  crumb = requests.get(url=crumbUrl, cookies=cookie, headers=headers).text
  return {'cookie': cookie, 'crumb': crumb}

def quote(symbols, credentials):
  url = apiBase + '/v7/finance/quote'
  params = {'symbols': ','.join(symbols), 'crumb': credentials['crumb']}
  response = requests.get(url, params=params, cookies=credentials['cookie'], headers=headers)
  quotes = response.json()['quoteResponse']['result']
  return quotes

credentials = getCredentials()
quotes = quote(['GOOG', 'TSLA'], credentials)
if quotes:
  for quote in quotes:
    print(f"{quote['symbol']} price is {quote['currency']} {quote['regularMarketPrice']}")

# GOOG price is USD 121.08
# TSLA price is USD 256.24

我使用了https://www.codeconvert.ai/javascript-to-python-converter加上一些修改


0
投票

我为 VBA 宏做了这个:

Public Function GetStockData() As String
    Dim qurl As String
    Dim cookie As String
    Dim crumb As String
    Dim req As Object
    Dim cookieurl As String

    cookieurl = "https://fc.yahoo.com" 'This page needs to return a cookie, query1.finance.yahoo does not return cookie.
    
    Set req = CreateObject("WinHttp.WinHttpRequest.5.1")
    
    'get cookie
    With req
        .Open "GET", cookieurl, False
        .setRequestHeader "REFERER", cookieurl
        .setRequestHeader "User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
        .Send
        
        cookie = .getResponseHeader("Set-Cookie") 'gets cookie and saves it.
    End With
   
    'get crumb
    With req
        .Open "GET", "https://query2.finance.yahoo.com/v1/test/getcrumb", False 'gets crumb, which must be attached to all quote calls
        .setRequestHeader "REFERER", cookieurl
        .setRequestHeader "User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
        .setRequestHeader "Cookie", cookie 'applies cookie to header, currently working without this, but probably good practice to use it
        .Send
        
        crumb = .responseText 'saves crumb
    End With
    
    qurl = "http://query1.finance.yahoo.com/v7/finance/quote?symbols=AAPL"
  
    qurl = qurl & "&crumb=" & crumb 'add crumb info from GetCookie sub
    

    'get data
    With req
        .Open "GET", qurl, False
        'header is needed but not specific, could probbaly remove a couple lines without creating a problem
        .setRequestHeader "REFERER", cookieurl
        .setRequestHeader "User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
        .setRequestHeader "Cookie", cookie
        .Send
        GetStockData = .responseText 'get data and return
    End With
End Function

© www.soinside.com 2019 - 2024. All rights reserved.