Yahoo Finance HTTP响应代码:401用于URL

时间:2017-07-02 01:07:45

标签: java

我正在尝试从雅虎财经创建程序下载历史数据,然后根据输入主类的股票代码显示去年的历史数据。

出于某种原因,我在尝试运行程序时不断收到401代码。如果我复制并粘贴到浏览器中,401错误中显示的URL会让我想去。

不确定我在这里做错了什么。

这是我的StockDownloader类的代码:

import java.util.GregorianCalendar;
import java.util.Calendar;
import java.util.ArrayList;
import java.net.URL;
import java.net.URLConnection;
import java.util.Scanner;


public class StockDownloader
{
    public static final int DATE = 0;
    public static final int OPEN = 1;
    public static final int HIGH = 2;   
    public static final int LOW = 3;
    public static final int CLOSE = 4;
    public static final int VOLUME = 6;
    public static final int ADJCLOSE = 5;

    private ArrayList<GregorianCalendar> dates;
    private ArrayList<Double> opens;
    private ArrayList<Double> highs;
    private ArrayList<Double> lows; 
    private ArrayList<Double> closes;
    private ArrayList<Integer> volumes;
    private ArrayList<Double> adjCloses;

    public StockDownloader (String symbol)
    {
        dates = new ArrayList<GregorianCalendar>();
        opens = new ArrayList<Double>();
        highs = new ArrayList<Double>();
        lows = new ArrayList<Double>();
        closes = new ArrayList<Double>();
        volumes = new ArrayList<Integer>();
        adjCloses = new ArrayList<Double>();

        //https://query1.finance.yahoo.com/v7/finance/download/IBM?period1=1467352800&period2=1498888800&interval=1d&events=history&crumb=2WsiR.p1KtI
        String url = "https://query1.finance.yahoo.com/v7/finance/download/"+symbol+"?period1=1467352800&period2=1498888800&interval=1d&events=history&crumb=2WsiR.p1KtI";
        try
        {
            URL yhoofin = new URL(url);
            URLConnection data = yhoofin.openConnection();
            Scanner input = new Scanner(data.getInputStream());
            if(input.hasNext())//skip line...it's just the header
                input.nextLine();

            //start reading data
            while(input.hasNextLine())
            {
            String line = input.nextLine();
            //TODO- connec tdata to the correct ArrayList
            System.out.println(line);
            }
        }

        catch (Exception e)
        {
            System.err.println(e);
        }

    }
    public ArrayList<GregorianCalendar> getDates()
    {
        return dates;
    }

    /*public ArrayList<Double> get Opens()
    {
    }*/

}

我的主类代码:

public class Stocks {

    public static void main(String[] args)
    {
        StockDownloader test = new StockDownloader("DCTH");
    }
}

请帮助

2 个答案:

答案 0 :(得分:1)

看起来雅虎已经改变了访问金融API的方式。您需要向URL连接添加cookie。已经改变了你的代码,它对我有用。

public class StockDownloader {
    public static final int DATE = 0;
    public static final int OPEN = 1;
    public static final int HIGH = 2;
    public static final int LOW = 3;
    public static final int CLOSE = 4;
    public static final int VOLUME = 6;
    public static final int ADJCLOSE = 5;

    private ArrayList<GregorianCalendar> dates;
    private ArrayList<Double> opens;
    private ArrayList<Double> highs;
    private ArrayList<Double> lows;
    private ArrayList<Double> closes;
    private ArrayList<Integer> volumes;
    private ArrayList<Double> adjCloses;

    private String finalCrumb;

    public StockDownloader(String symbol) {
        dates = new ArrayList<GregorianCalendar>();
        opens = new ArrayList<Double>();
        highs = new ArrayList<Double>();
        lows = new ArrayList<Double>();
        closes = new ArrayList<Double>();
        volumes = new ArrayList<Integer>();
        adjCloses = new ArrayList<Double>();

        try {

            // Hit the below URL to get the cookies and the crumb value to access the finance API
            String mainURL = "https://uk.finance.yahoo.com/quote/"+symbol+"/history";
            Map<String, List<String>> setCookies = setCookies(mainURL);
            // https://query1.finance.yahoo.com/v7/finance/download/IBM?period1=1467352800&period2=1498888800&interval=1d&events=history&crumb=2WsiR.p1KtI

            // will need to append the crumb in the end to the below URL to have the actual crumb rather than the hardcoded one
            String url = "https://query1.finance.yahoo.com/v7/finance/download/" + symbol
                    + "?period1=1467352800&period2=1498888800&interval=1d&events=history&crumb=" + finalCrumb;
            URL yhoofin = new URL(url);
            URLConnection data = yhoofin.openConnection();

            // get the list of Set-Cookie cookies from response headers
            List<String> cookies = setCookies.get("Set-Cookie");
            if (cookies != null) {
                for (String c : cookies)
                    data.setRequestProperty("Cookie", c);
            }
            Scanner input = new Scanner(data.getInputStream());
            if (input.hasNext())// skip line...it's just the header
                input.nextLine();

            // start reading data
            while (input.hasNextLine()) {
                String line = input.nextLine();
                // TODO- connec tdata to the correct ArrayList
                System.out.println(line);
            }
            input.close();
        }

        catch (Exception e) {
            System.err.println(e);
        }

    }

    // This method extracts the crumb and is being called from setCookies() method
    private String searchCrumb(URLConnection con) throws IOException {
        String crumb = null;
        InputStream inStream = con.getInputStream();
        InputStreamReader irdr = new InputStreamReader(inStream);
        BufferedReader rsv = new BufferedReader(irdr);

        Pattern crumbPattern = Pattern.compile(".*\"CrumbStore\":\\{\"crumb\":\"([^\"]+)\"\\}.*");

        String line = null;
        while (crumb == null && (line = rsv.readLine()) != null) {
            Matcher matcher = crumbPattern.matcher(line);
            if (matcher.matches())
                crumb = matcher.group(1);
        }
        rsv.close();
        System.out.println("Crumb is : "+crumb);
        return crumb;
    }


    // This method extracts the cookies from response headers and passes the same con object to searchCrumb()
    // method to extract the crumb and set the crumb value in finalCrumb global variable
    private Map<String, List<String>> setCookies(String mainUrl) throws IOException {
        // "https://finance.yahoo.com/quote/SPY";
        Map<String, List<String>> map = new HashMap<String, List<String>>();
        URL url = new URL(mainUrl);
        URLConnection con = url.openConnection();
        finalCrumb = searchCrumb(con);
        for (Map.Entry<String, List<String>> entry : con.getHeaderFields().entrySet()) {
            if (entry.getKey() == null || !entry.getKey().equals("Set-Cookie"))
                continue;
            for (String s : entry.getValue()) {
                map.put(entry.getKey(), entry.getValue());
                System.out.println(map);
            }
        }

        return map;

    }

    public ArrayList<GregorianCalendar> getDates() {
        return dates;
    }

}

有关于财务API here的详细信息。

试一试!

答案 1 :(得分:0)

401错误代码表示用户未经授权。再看看YQL,如果您确定所做的一切都是正确的,但问题仍然存在,请查看此library。这使得使用Yahoo Finance API更加轻松。