quandl api_c++ cannot retrieve data

时间:2015-12-14 18:11:24

标签: c++ api quandl

I am wondering if someone could share his experiene on using quandl api_c to retrieve data:

Below is the sample code:

#include <iostream>
#include "C:\local\quandl.h"
//Reference: https://github.com/zafuer/QuandlAPI_C  

int main()
{
quandl ql;
    ql.auth("<code>"); // Replace <code> with your own token.
    ql.get("GOOG/PINK_TCEHY");
    return 0;
}

It does compile, but retrieves in the project path PINK_TCEHY.csv with unexpected xml info:

<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.4.6 (Ubuntu)</center>
</body>
</html>

Could someone be able to explain such phenomenon?

Best,

2 个答案:

答案 0 :(得分:0)

Quandl不再支持HTTP请求,现在请求必须通过HTTPS进行,我使用curl for windows:

#include <stdio.h>
#include <curl/curl.h>

int main(void)
{
  CURL *curl;
  CURLcode res;

  curl = curl_easy_init();
  if(curl) {
    /* First set the URL that is about to receive our POST. This URL can
       just as well be a https:// URL if that is what should receive the
       data. */
    curl_easy_setopt(curl, CURLOPT_URL, "https://www.quandl.com/api/v3/datasets/WIKI/FB/data");

    /* Perform the request, res will get the return code */
    res = curl_easy_perform(curl);

    /* always cleanup */
    curl_easy_cleanup(curl);
  }
  return 0;
}

对于linux,使用OpenSSL的api将是:

/*
 * quandl(linux).h
 *
 *  Created on: 30/09/2013 (Updated on 10/09/2014) ((Revised on 15/08/2016))
 *      Author: Zhiwei Fu
 *      Revision: Jose Marqués Fernández    http://www.epigijon.uniovi.es/
 */

/* This programme is free software. It is developed by Dr Zhiwei Fu as a product
   contributing to quandl.com.
   This programme is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY, without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/

//OpenSSL required, for install on ubuntu: sudo apt-get install libssl-dev  
//for compile: g++ xxx.cpp -std=c++11 -lssl -lcrypto -o xxx

#ifndef QUANDL_H_
#define QUANDL_H_
#include <iostream>
#include <fstream> //for perror()
#include <string> // string for c++
#include <string.h> // for memset()/bzero() For C
#include <sys/socket.h> 
#include <netinet/in.h> // for sockaddr_in, hotons
#include <arpa/inet.h> // for inet_addr
#include <netdb.h> //for gethostbyname(), gethostbyaddr()
#include <netinet/tcp.h> // for TCP_NODELAY
#include <time.h> // time.h

// for https
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <stdlib.h>
#include <memory.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <stdarg.h>

#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

//using namespace std;

class quandl {
    public:

        quandl(){


                };
        ~quandl(){};
        // To store the token in "AuthCode", which is a public variable in the class.
        void auth(std::string code){
            AuthCode = code;
        }

        //To download file from the website defined by the first 
        //argument.
        // To determine the website address by the token stored in "code"
        // and call the function "download"
        void get(std::string code){
            //Set optional variables by default
            std::string order = "asc"; 
            std::string type = "csv";

            std::string website = "https://www.quandl.com/api/v3/datasets/" + code 
                + "." + type + "?sort_order=" + order;
            if(AuthCode.length() == 0){
                std::cout << "It would appear you are\'nt using an authentication"
                  << " token. Please visit https://www.quandl.com/help/c++"
                  << " or your usage may be limited.\n";
            }
            else{
                website += "&api_key=" + AuthCode;
            }

            std::string FileName;
            int iLength = code.length();
            for (int i=0; i < iLength; i++){
                if(code.substr(i, 1) == "/"){
                    FileName = code.substr(i+1, iLength - i -1);
                    break;
                }
            }

            download(website, FileName, type);
            return;
        }

        // All parameters are prescribed by users.
        // 1. Quandl code;
        // 2. Ascending/descending order;
        // 3. Start date;
        // 4. End date;
        // 5. Transformation;
        // 6. collapse;
        // 7. Rows;
        // 8. Output type
        // There are 7 optional arguments compared to the one above.
        void get(std::string code, std::string order, std::string StartDate, std::string EndDate,
            std::string transformation, std::string collapse, std::string rows, std::string type){

            std::string website = "https://www.quandl.com/api/v3/datasets/" + code 
                + "." + type + "?sort_order=" + order;
            if(AuthCode.length() == 0){
                std::cout << "It appear you are\'nt using an authentication"
                  << " token. Please visit https://www.quandl.com/help/api for getting one"
                  << " ; otherwise your usage may be limited.\n";
            }
            else{
                website += "&api_key=" + AuthCode;
            }

            website += "&trim_start=" + StartDate;
            website += "&trim_end=" + EndDate;
            website += "&transformation=" + transformation;
            website += "&collapse=" + collapse;
            website += "&rows=" + rows;

            std::string FileName;
            int iLength = code.length();
            for (int i=0; i < iLength; i++){
                if(code.substr(i, 1) == "/"){
                    FileName = code.substr(i+1, iLength - i -1);
                    break;
                }
            }

            download(website, FileName, type);
        }
    private: 
        std::string AuthCode;
        // This void function "download" is to download a file from internet.
        // The "download" function is developed with a general purpose of downloading
        // files from internet. It is based on the socket programming.
        void download(std::string website, std::string FileName, std::string FileType){

                    struct sockaddr_in ServAddr;
                    struct hostent *ServInf;
                    int sockfd;
                    int iMessage = 1048576; //1 MB for the buff storage
                    char message[iMessage];
                    std::string request = "GET ";
                    std::ofstream fid;
                    int iStart, iEnd, iLength;

                    SSL_CTX *ctx;
                    SSL *ssl;                 
                    OpenSSL_add_all_algorithms();
                    ERR_load_crypto_strings();
                    SSL_load_error_strings();

                    if(SSL_library_init() < 0){
                        std::cerr<<"OpenSSL error"<<std::endl;
                        return;
                    }

                    ctx = SSL_CTX_new (SSLv23_client_method ());
                    SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);

                    //To define the server's address.
                    memset(&ServAddr, 0, sizeof(ServAddr));
                    std::string host;
                    iLength = website.length();
                    iStart = 0; iEnd = iLength - 1;
                    if(website.substr(0,8) == "https://") iStart = 8;
                    else if(website.substr(0,7) == "http://") iStart = 7;
                    for(int i = iStart; i<iLength; i++){
                        if(website.substr(i, 1)=="/"){
                            iEnd = i - 1;
                            break;
                        }
                    }
                    host = website.substr(iStart, iEnd - iStart + 1);

                    ServInf = gethostbyname(host.c_str());
                    if(ServInf == NULL){
                        std::cerr<<"HostName error"<<std::endl;
                        return;
                    }

                    //Get a socket
                    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
                        std::cerr<<"Socket error"<<std::endl;
                        return;
                    }

                    memset(&ServAddr, 0, sizeof(ServAddr));
                    ServAddr.sin_family = AF_INET;
                    ServAddr.sin_port = htons(443);
                    ServAddr.sin_addr.s_addr = *(long*)(ServInf->h_addr);

                    if ( connect(sockfd, (struct sockaddr*)&ServAddr, sizeof(ServAddr)) == -1 ) {
                       std::cerr<<"Conection error"<<std::endl;
                       return;
                    }

                    ssl = SSL_new(ctx); 
                    SSL_set_fd(ssl, sockfd);

                    SSL_connect(ssl);

                    // To send the request.
                    request += website + " HTTP/1.1\r\nHost: " + host + "\r\nConnection: close\r\n\r\n";                    
                    SSL_write(ssl, request.c_str(), request.length());

                    // To initiate the file.
                    fid.open((FileName + "." + FileType).c_str());
                    if(fid.fail()){
                        std::cerr << "OpeningFile error" << std::endl;
                        return;
                    }

                    // To read dataflow for the file.
                    int iRecv = 1;                    
                    std::string RcvDt;

                    while (iRecv != 0 && iRecv != -1){
                        memset(message, '\0', sizeof(message));
                       iRecv= SSL_read(ssl, message, iMessage);
                        RcvDt+=std::string(message);

                    }
                    std::string initS="\r\n\r\n";
                    std::string servR="\r\n";

                    std::size_t found = RcvDt.find(initS);
                    if (found!=std::string::npos){
                        RcvDt.erase(0,found+10);
                    }
                    while((found!=std::string::npos)&&(found<RcvDt.size()-8)){
                        found = RcvDt.find(servR);
                        if(found<(RcvDt.size()-8)){
                            RcvDt.erase(found,8);
                        }
                    }
                    fid.write(RcvDt.c_str(), RcvDt.size());


                    // To close the downloaded file
                    fid.close();
                    if(iRecv == -1){
                        std::cerr<<"SSL_read error"<<std::endl;
                        return;
                    }


                    SSL_free(ssl);
                    close(sockfd);
                    SSL_CTX_free(ctx);




        }
};

#endif /* QUANDL_H_ */

我希望这会有用

答案 1 :(得分:0)

您可以使用ql_fetcher作为替代轻量级C ++标头库来下载Quandl数据。您还需要将libcurl与您的项目相关联。

在您的情况下,您可以像这样使用它:

#define  QL_FETCHER_IMPL      // define only once in your project
#include "ql_fetcher"
#include <string>

int main() {
   std::string raw_data = ql_fetcher::fetch("PINK_TCEHY", "GOOG")
      .api_key("<code>").make().get().str();

   return 0;
}