从新的Yahoo Finance历史数据下载csv出错

时间:2017-05-22 05:23:41

标签: csv cookies yahoo-finance

我已经尝试为新的雅虎财务历史数据制作一些代码,因为旧的API正式死亡。代码如下:

Private Function DownloadData(ByVal StockSymbol As String)

    Try

        'https://query1.finance.yahoo.com/v7/finance/download/CPG.TO?period1=1492824351&period2=1495416351&interval=1d&events=history&crumb=M3Ig5MvcK77

        Dim Period1 As Integer = (New DateTime(2007, 1, 1, 0, 0, 0) - New DateTime(1980, 1, 1, 0, 0, 0)).TotalSeconds
        Dim Period2 As Integer = (DateTime.UtcNow - New DateTime(1980, 1, 1, 0, 0, 0)).TotalSeconds

        Dim csvData As String = String.Empty

        Using Web As New WebClient

            Dim strm As Stream = Web.OpenRead("https://finance.yahoo.com/quote/" & StockSymbol & "/history?p=" & StockSymbol)

            Dim Crumb As String = ScrapeCrumb(strm)

            Dim s As String = "https://query1.finance.yahoo.com/v7/finance/download/" & StockSymbol &
                                "?period1=" & Period1.ToString & "&period2=" & Period2.ToString & "&interval=1d&events=history&crumb=" & Crumb
            csvData = Web.DownloadString(s)

        End Using

        Return csvData

    Catch ex As Exception

        Return String.Empty

    End Try

End Function
Private Function ScrapeCrumb(ByVal strm As Stream) As String

    Try

        Dim Output As String = String.Empty

        Using sr As New StreamReader(strm)
            Output = sr.ReadToEnd()
            ' Close and clean up the StreamReader
            sr.Close()
        End Using

        Dim Result As String = Output.Remove(0, Output.IndexOf("CrumbStore"))
        Result = Result.Remove(0, 22)
        Result = Result.Remove(Result.IndexOf("}"), Result.Length - Result.IndexOf("}"))
        Result = Result.Remove(Result.Length - 1, 1)

        Return Result

    Catch ex As Exception

        Return String.Empty

    End Try

End Function

但我一直收到错误

  

远程服务器返回错误:(401)未经授权。

我觉得它与cookies / crumb交易有关,但我正在抓它,所以我不确定为什么这不授予下载文件的权限。有没有人有任何想法?

编辑:使用vb语言

1 个答案:

答案 0 :(得分:3)

你得到错误"(401)未经授权"因为你没有有效的cookie(cookie" B")值。

我成功地设计了一个.NET类来从Yahoo Finance获得有效的令牌(cookie和crumb)

要从新的Yahoo Finance获取历史数据的完整API库,您可以访问Github中的YahooFinanceAPI

这是获取cookie和crumb的类

<强> Token.cs

using System;
using System.Diagnostics;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;

namespace YahooFinanceAPI
{
    /// <summary>
    /// Class for fetching token (cookie and crumb) from Yahoo Finance
    /// Copyright Dennis Lee
    /// 19 May 2017
    /// 
    /// </summary>
    public class Token
    {
        public static string Cookie { get; set; }
        public static string Crumb { get; set; }

        private static Regex regex_crumb;
        /// <summary>
        /// Refresh cookie and crumb value Yahoo Fianance
        /// </summary>
        /// <param name="symbol">Stock ticker symbol</param>
        /// <returns></returns>
        public static bool Refresh(string symbol = "SPY")
        {

            try
            {
                Token.Cookie = "";
                Token.Crumb = "";

                string url_scrape = "https://finance.yahoo.com/quote/{0}?p={0}";
                //url_scrape = "https://finance.yahoo.com/quote/{0}/history"

                string url = string.Format(url_scrape, symbol);

                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);

                request.CookieContainer = new CookieContainer();
                request.Method = "GET";

                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                {

                    string cookie = response.GetResponseHeader("Set-Cookie").Split(';')[0];

                    string html = "";

                    using (Stream stream = response.GetResponseStream())
                    {
                        html = new StreamReader(stream).ReadToEnd();
                    }

                    if (html.Length < 5000)
                        return false;
                    string crumb = getCrumb(html);
                    html = "";

                    if (crumb != null)
                    {
                        Token.Cookie = cookie;
                        Token.Crumb = crumb;
                        Debug.Print("Crumb: '{0}', Cookie: '{1}'", crumb, cookie);
                        return true;
                    }

                }

            }
            catch (Exception ex)
            {
                Debug.Print(ex.Message);
            }

            return false;

        }

        /// <summary>
        /// Get crumb value from HTML
        /// </summary>
        /// <param name="html">HTML code</param>
        /// <returns></returns>
        private static string getCrumb(string html)
        {

            string crumb = null;

            try
            {
                //initialize on first time use
                if (regex_crumb == null)
                    regex_crumb = new Regex("CrumbStore\":{\"crumb\":\"(?<crumb>\\w+)\"}", 
                    RegexOptions.CultureInvariant | RegexOptions.Compiled, TimeSpan.FromSeconds(5));

                MatchCollection matches = regex_crumb.Matches(html);

                if (matches.Count > 0)
                {
                    crumb = matches[0].Groups["crumb"].Value;
                }
                else
                {
                    Debug.Print("Regex no match");
                }

                //prevent regex memory leak
                matches = null;

            }
            catch (Exception ex)
            {
                Debug.Print(ex.Message);
            }

            GC.Collect();
            return crumb;

        }

    }
}