zoukankan      html  css  js  c++  java
  • 使用CURL读取HTTP数据到字符串或者文件中

    这两天简单研究了下CURL访问网站读取数据的方式,做了简单的实验,思路很简单,就是提供一个URL,然后从URL返回的数据读取出来,显示到控制台,或者存储到文件中。具体的描述以及注意事项,代码的注释中都有写明。

    上代码。

    // DemoLibcurl.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    
    #define CURL_STATICLIB            // 由于我使用的是CURL静态链接,所以需要定义上这个宏
    #include "http://www.cnblogs.com/../include/curl/curl.h"
    
    // 一下三个lib为libcurl.lib所依赖的三个库
    #pragma comment(lib, "Wldap32.lib")
    #pragma comment(lib, "Ws2_32.lib")
    #pragma comment(lib, "Advapi32.lib")
    
    #ifdef _DEBUG
    #pragma comment(lib,"http://www.cnblogs.com/../lib/libcurld.lib")
    #else
    #pragma comment(lib,"http://www.cnblogs.com/../lib/libcurl.lib")
    #endif
    
    #include <iostream>
    #include <string>
    using namespace std;
    
    
    // 定义一个break宏
    #define BREAK_ON_NOT_EQUAL(compareValue, resultValue) {if((compareValue) != (resultValue))break;}
    
    
    // 执行输出到标准输出流
    bool PerformToStdout(IN CURL* nphEasycurl);
    
    // curl指定格式的回调函数
    size_t WriteToString(void *buffer, size_t size, size_t nmemb, void *userp);
    
    size_t WriteToFile(void *buffer, size_t size, size_t nmemb, void *userp);
    
    // 执行输出到字符串
    bool PerformToString(IN CURL* nphEasycurl, IN string& rstrBuffer);
    
    // 执行输出到文件
    bool PerformToFile(IN CURL* nphEasycurl, IN char* nscFileName, bool nbIsUseCallBackMethod = false);
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        // 进行初始化
        CURL* lphEasycurl = curl_easy_init(); 
        do 
        {
            // 初始化失败
            if(NULL == lphEasycurl)
            {
                cout << "Error: Init curl handle failed." << endl;
                break;
            }
    
            // 获取当前使用的curl库的版本信息
            curl_version_info_data* ldVersionInfo = curl_version_info(CURLVERSION_NOW);
            if(NULL != ldVersionInfo && ldVersionInfo->age > 0)
            {
                //// 判断是否支持所需要的功能
                //if(1 !=  (ldVersionInfo->features & CURL_VERSION_GSSNEGOTIATE))        // 不明白这里要用那个宏去进行判断才表示支持HTTP
                //{
                //    cout << "Error: Current Curl version do`nt support HTTP." << endl;
                //    break;
                //}
            }
            else        // 获取版本信息失败
            {
                cout << "Error: Get version info of Curl failed." << endl;
                break;
            }
    
            // 设置接受错误信息的缓存,CURL_ERROR_SIZE为curl要求的最小大小
            char lscErrBuffer[CURL_ERROR_SIZE];            
            curl_easy_setopt(lphEasycurl, CURLOPT_ERRORBUFFER, &lscErrBuffer);            // 接受错误描述
    
            // 设置URL
            curl_easy_setopt(lphEasycurl, CURLOPT_URL, "http://www.cnn.com/"); 
    
            // 执行
            int liOutputType = 2;                // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~通过更改这个值,来尝试不同的方式
            bool lbIsPerformSuccess = false;
            string lstrDataBuffer;
            switch(liOutputType)
            {
            case 1:                // 输出到字符串
                {
                    lbIsPerformSuccess = PerformToString(lphEasycurl, lstrDataBuffer);
                }
                break;
    
            case 2:                // 输出到文件
                {
                    lbIsPerformSuccess = PerformToFile(lphEasycurl, "output.txt", true);        // ~~~~~~~~~更改第三个参数来调用不同的实现方式
                }
                break;
    
            default:            // 输出到标准输出
                {
                    lbIsPerformSuccess = PerformToStdout(lphEasycurl);
                }
                break;
            }
            
            // 执行失败,输出错误描述
            if(false == lbIsPerformSuccess)
            {
                cout << "Error: " << lscErrBuffer << endl;
                break;
            }
    
            // 根据设置的类型进行输出
            if(1 == liOutputType)
            {
                cout  << "The data read from url:" << lstrDataBuffer.c_str() << endl;
            }
            else if(2 == liOutputType)
            {
                cout << "Success: The data have saved to output.txt" << endl;
            }
    
    
        } while (false);
    
        // 清空初始化数据
        if(NULL != lphEasycurl)
            curl_easy_cleanup(lphEasycurl); 
    
        cout<<endl<<"Press anykey to continue!"<<endl;
        getchar();
        return 0;
    }
    
    
    
    
    
    bool PerformToStdout(IN CURL* nphEasycurl)
    {
        bool lbResult = false;
        do 
        {
    
            if(CURLE_OK != curl_easy_perform(nphEasycurl))
                break;
    
            lbResult = true;
        } while (false);
    
        return lbResult;
    }
    
    
    
    
    // 功能:
    //        libcurl写数据所使用的标准回调函数格式
    // 参数:
    //        buffer所指向数据块的字节数为size * nmemb,注意不会以0结尾。
    //        userp是通过设置CURLOPT_WRITEDATA属性传进来的指针
    // 返回值:
    //        通常作为实际处理的字节数,如果处理的总字节数和传入的字节总数不同,curl将中止操作并返回错误码CURLE_WRITE_ERROR
    size_t WriteToString(void *buffer, size_t size, size_t nmemb, void *userp)
    {
        *((std::string*)userp) += (char*)buffer;        // 不是说不是以0结尾的吗?这里用这种方式不会访问越界么?
    
        return size * nmemb;
    }
    
    bool PerformToString(IN CURL* nphEasycurl, IN string& rstrBuffer)
    {
        bool lbResult = false;
        do 
        {
            curl_easy_setopt(nphEasycurl, CURLOPT_WRITEFUNCTION, WriteToString);    // 如果不提供这个回调函数,curl将会将数据输出到stdout中。
            curl_easy_setopt(nphEasycurl, CURLOPT_WRITEDATA, &rstrBuffer);
            
            if(CURLE_OK != curl_easy_perform(nphEasycurl))
                break;
    
            lbResult = true;
        } while (false);
    
        return lbResult;
    }
    
    // 同WriteToString
    size_t WriteToFile(void *buffer, size_t size, size_t nmemb, void *userp)
    {
        FILE* lphFile = (FILE*)userp;
        if(NULL != lphFile)
        {
            fwrite(buffer, size, nmemb, lphFile);
        }
    
        return size * nmemb;
    }
    
    bool PerformToFile(IN CURL* nphEasycurl, IN char* nscFileName, bool nbIsUseCallBackMethod)
    {
        bool lbResult = false;
        FILE* lphFile = NULL;                // CURL要求必须使用FILE
        do 
        {
            if(NULL == nscFileName)
                break;
    
            // 打开文件
            lphFile = fopen(nscFileName, "wb+");
            if(NULL == lphFile)
            {
                cout << "file open failed." << endl;
                break;
            }
            
            if(false != nbIsUseCallBackMethod)            // 使用回调方式
            {
                // 方式1,将File*传递给回调函数,自己进行处理。
                BREAK_ON_NOT_EQUAL(CURLE_OK, curl_easy_setopt(nphEasycurl, CURLOPT_WRITEFUNCTION, WriteToFile));
            }
    
            // 方式2,直接将FILE*传递给CURL去进行处理,!注意,CURL默认会使用fwrite写入数据,这也是为什么并且只能传入FILE*的原因。
            BREAK_ON_NOT_EQUAL(CURLE_OK, curl_easy_setopt(nphEasycurl, CURLOPT_WRITEDATA, lphFile));
    
            // 方式3,用PerformToFile,然后将返回的数据写入File中,这里不进行实验
    
            // 执行
            BREAK_ON_NOT_EQUAL(CURLE_OK, curl_easy_perform(nphEasycurl));
    
            lbResult = true;
        } while (false);
    
        if(NULL != lphFile)
            fclose(lphFile);
    
        return lbResult;
    }
  • 相关阅读:
    【百度搜索研发部】以求医为例谈搜索引擎排序算法的基础原理(转)
    TF-IDF与余弦相似性的应用(三):自动摘要
    TF-IDF与余弦相似性的应用(一):自动提取关键词
    TF-IDF与余弦相似性的应用(二):找出相似文章
    技术向:一文读懂卷积神经网络CNN(转)
    [透析] 卷积神经网络CNN究竟是怎样一步一步工作的?(转)
    像素间的基本关系-距离(转)
    Swift学习笔记-字符串和字符(Strings and Characters)-比较字符串 (Comparing Strings)
    Swift学习笔记-基本运算符(Basic Operators)-空合运算符(Nil Coalescing Operator)
    Swift学习笔记-基本运算符(Basic Operators)-求余运算符
  • 原文地址:https://www.cnblogs.com/monotone/p/2772140.html
Copyright © 2011-2022 走看看