0
votes

I have been using the Yahoo Financial API to download historical stock data from Yahoo. As has been reported on this site, as of mid May, the old API was discontinued. There have been many posts addressed the the form of the new call, e.g.:

https://query1.finance.yahoo.com/v7/finance/download/AAPL?period1=315561600&period2=1496087439&interval=1d&events=history&crumb=XXXXXXXXXXX

As well as methods for obtaining the crumb:

Yahoo Finance URL not working

But I must be misunderstanding what the procedure is as I always get an error saying that it "Failed to open stream: HTTP request failed. HTTP/1.0 201 Unauthorized".

Below is my code. Any and all assistance is welcome. I have to admit that I am an old Fortran programmer and my coding reflects this.

Good Roads

Bill

$ticker = "AAPL";
$yahooURL="https://finance.yahoo.com/quote/" .$ticker ."/history";
$body=file_get_contents($yahooURL);
$headers=$http_response_header;
$icount = count($headers);
for($i = 0; $i < $icount; $i ++)
{
    $istart = -1;
    $istop = -1;
    $istart = strpos($headers[$i], "Set-Cookie: B=");
    $istop = strpos($headers[$i], "&b=");
    if($istart > -1 && $istop > -1)
    {
        $Cookie = substr ( $headers[$i] ,$istart+14,$istop - ($istart + 14));
    }
}

$istart = strpos($body,"CrumbStore") + 22;
$istop = strpos($body,'"', $istart);
$Crumb = substr ( $body ,$istart,$istop - $istart);

$iMonth = 1;
$iDay = 1;
$iYear = 1980;
$timestampStart = mktime(0,0,0,$iMonth,$iDay,$iYear);
$timestampEnd = time();

$url =  "https://query1.finance.yahoo.com/v7/finance/download/".$ticker."?period1=".$timestampStart."&period2=".$timestampEnd."&interval=1d&events=history&crumb=".$Cookie."";

while (!copy($url, $newfile) && $iLoop < 10)
{
    if($iLoop == 9) echo "Failed to download data." .$lf;
    $iLoop = $iLoop + 1;
    sleep(1);
}
2
Possible duplicate of Yahoo Finance Historical data downloader url is not workinguser7365852

2 Answers

0
votes

@Craig Cocca this isn't exactly a duplicate because the reference you gave gives a solution in python which for those of us who use php but haven't learnt python doesn't help much. I'd love to see as solution with php. I've examinied the yahoo page and am able to extract the crumb but can't work out how to put it into a stream and GET call. My latest (failed) effort is:

        $headers = [
        "Accept" => "*/*",
        "Connection" => "Keep-Alive",
        "User-Agent" => sprintf("curl/%s", curl_version()["version"])       
    ];

    // open connection to Yahoo
    $context = stream_context_create([
        "http" => [
            "header" => (implode(array_map(function($value, $key) { return sprintf("%s: %s\r\n", $key, $value); }, $headers, array_keys($headers))))."Cookie: $Cookie",
            "method" => "GET"
        ]
    ]);
    $handle = @fopen("https://query1.finance.yahoo.com/v7/finance/download/{$symbol}?period1={$date_now}&period2={$date_now}&interval=1d&events=history&crumb={$Crumb}", "r", false, $context);
    if ($handle === false)
    {
        // trigger (big, orange) error
        trigger_error("Could not connect to Yahoo!", E_USER_ERROR);
        exit;
    } 

    // download first line of CSV file
    $data = fgetcsv($handle);

The two dates are unix coded dates i.e.: $date_now = strtotime($date);

0
votes

I've now managed to download share price history. At the moment I'm only taking the current price figures but my download method receives historical data for the past year. (i.e. until Yahoo decides to put some other block on the data). My solution uses the "simple_html_dom.php" parser which I've added to my /includes folder. Here is the code (modified from the original version from the Harvard CS50 course which I recommend for beginners like me):

function lookup($symbol)
{
// reject symbols that start with ^
   if (preg_match("/^\^/", $symbol))
   {
       return false;
   }
// reject symbols that contain commas
   if (preg_match("/,/", $symbol))
   {
       return false;
   }
   // body of price history search
$sym = $symbol;
   $yahooURL='https://finance.yahoo.com/quote/'.$sym.'/history?p='.$sym;

// get stock name
$data = file_get_contents($yahooURL);
    $title = preg_match('/<title[^>]*>(.*?)<\/title>/ims', $data, $matches) ? $matches[1] : null;

$title = preg_replace('/[[a-zA-Z0-9\. \| ]* \| /','',$title);
$title = preg_replace('/ Stock \- Yahoo Finance/','',$title);
$name = $title;

// get price data - use simple_html_dom.php (added to /include)
$body=file_get_html($yahooURL);
$tables = $body->find('table');
$dom = new DOMDocument();
$elements[] = null;
$dom->loadHtml($tables[1]); 
$x = new DOMXpath($dom);
$i = 0;
foreach($x->query('//td') as $td){
        $elements[$i] = $td -> textContent." ";
    $i++;
}
$open = floatval($elements[1]); 
$high = floatval($elements[2]);
$low = floatval($elements[3]);
$close = floatval($elements[5]);
$vol = str_replace( ',', '', $elements[6]);
$vol = floatval($vol);
$date = date('Y-m-d');
$datestamp = strtotime($date);
$date = date('Y-m-d',$datestamp);
   // return stock as an associative array
   return [
        "symbol" => $symbol,
        "name" => $name,
        "price" => $close,
        "open" => $open,
        "high" => $high,
        "low" => $low,
        "vol" => $vol,
        "date" => $date
   ];
}