url = 'https://query2.finance.yahoo.com/v7/finance/quote?symbols=TSLA&fields=regularMarketPreviousClose®ion=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 吗?
这对我有用。
set-cookie
,然后在后续调用中使用[crumb-value]
并使用 cookie 进行 HTTP GET 调用 https://query2.finance.yahoo.com/v7/finance/quote?symbols=TSLA&crumb=[crumb-value]这是一个基于 @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)
为了完成,让我添加一个 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}`)
}
}
我是用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;
}
}
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
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加上一些修改
我为 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