将CURL内容结果保存到C ++中的string中
int main(void) { CURL *curl; CURLcode res; curl = curl_easy_init(); if(curl) { curl_easy_setopt(curl, CURLOPT_URL, "http://www.google.com"); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); res = curl_easy_perform(curl); curl_easy_cleanup(curl); } _getch(); return 0; }
string contents =“”;
我想将curl html内容的结果保存在一个string中,我该怎么做? 这是一个愚蠢的问题,但不幸的是,我无法findCURL的CURL示例中的任何地方,谢谢!
您将不得不使用CURLOPT_WRITEFUNCTION
来设置callback书写。 我现在无法testing编译这个,但函数应该看起来接近;
static std::string readBuffer; static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; readBuffer.append(contents, realsize); return realsize; }
然后通过做,
readBuffer.clear(); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); // ...other curl options res = curl_easy_perform(curl);
调用之后, readBuffer
应该有你的内容。
编辑:您可以使用CURLOPT_WRITEDATA
来传递缓冲区string,而不是使其成为静态。 在这种情况下,为了简单起见,我只是将其设为静态 一个好的页面(除了上面的链接示例)在这里是对这些选项的解释。
编辑2:按照要求,这里是一个完整的工作示例,没有静态string缓冲区;
#include <iostream> #include <string> #include <curl/curl.h> static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) { ((std::string*)userp)->append((char*)contents, size * nmemb); return size * nmemb; } int main(void) { CURL *curl; CURLcode res; std::string readBuffer; curl = curl_easy_init(); if(curl) { curl_easy_setopt(curl, CURLOPT_URL, "http://www.google.com"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); res = curl_easy_perform(curl); curl_easy_cleanup(curl); std::cout << readBuffer << std::endl; } return 0; }
这可能不会马上工作,但应该给你一个想法:
#include <string> #include <curl.h> #include <stdio.h> size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) { size_t written; written = fwrite(ptr, size, nmemb, stream); return written; } int main() { std::string tempname = "temp"; CURL *curl; CURLcode res; curl = curl_easy_init(); if(curl) { FILE *fp = fopen(tempname.c_str(),"wb"); curl_easy_setopt(curl, CURLOPT_URL, "http://www.google.com"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); res = curl_easy_perform(curl); curl_easy_cleanup(curl); fclose(fp); fp = fopen(tempname.c_str(),"rb"); fseek (fp , 0 , SEEK_END); long lSize = ftell (fp); rewind(fp); char *buffer = new char[lSize+1]; fread (buffer, 1, lSize, fp); buffer[lSize] = 0; fclose(fp); std::string content(buffer); delete [] buffer; } }
基于@JoachimIsaksson的回答,这是一个更详细的输出,处理内存不足,并限制了curl的最大输出(因为CURLOPT_MAXFILESIZE限制仅基于头信息,而不是传输的实际大小)。
#DEFINE MAX_FILE_SIZE = 10485760 //10 MiB size_t curl_to_string(void *ptr, size_t size, size_t count, void *stream) { if(((string*)stream)->size() + (size * count) > MAX_FILE_SIZE) { cerr<<endl<<"Could not allocate curl to string, output size (current_size:"<<((string*)stream)->size()<<"bytes + buffer:"<<(size * count) << "bytes) would exceed the MAX_FILE_SIZE ("<<MAX_FILE_SIZE<<"bytes)"; return 0; } int retry=0; while(true) { try{ ((string*)stream)->append((char*)ptr, 0, size*count); break;// successful }catch (const std::bad_alloc&) { retry++; if(retry>100) { cerr<<endl<<"Could not allocate curl to string, probably not enough memory, aborting after : "<<retry<<" tries at 10s apart"; return 0; } cerr<<endl<<"Could not allocate curl to string, probably not enough memory, sleeping 10s, try:"<<retry; sleep(10); } } return size*count; }
出来了有用的,但简单的解决scheme,它重载std :: ostream :: operator <<
#include <ostream> #include <curl/curl.h> size_t curlCbToStream ( char * buffer, size_t nitems, size_t size, std::ostream * sout ) { *sout << buffer; return nitems * size; } std::ostream & operator<< ( std::ostream & sout, CURL * request ) { ::curl_easy_setopt(request, CURLOPT_WRITEDATA, & sout); ::curl_easy_setopt(request, CURLOPT_WRITEFUNCTION, curlCbToStream); ::curl_easy_perform(request); return sout; }
采取的方法可能的缺点可能是:
typedef void CURL;
这意味着它涵盖了所有已知的指针types。
在我的博客上,我发布了一个简单的包装类来执行这个任务。
用法示例:
#include "HTTPDownloader.hpp" int main(int argc, char** argv) { HTTPDownloader downloader; std::string content = downloader.download("https://stackoverflow.com"); std::cout << content << std::endl; }
这是头文件:
/** * HTTPDownloader.hpp * * A simple C++ wrapper for the libcurl easy API. * * Written by Uli Köhler (techoverflow.net) * Published under CC0 1.0 Universal (public domain) */ #ifndef HTTPDOWNLOADER_HPP #define HTTPDOWNLOADER_HPP #include <string> /** * A non-threadsafe simple libcURL-easy based HTTP downloader */ class HTTPDownloader { public: HTTPDownloader(); ~HTTPDownloader(); /** * Download a file using HTTP GET and store in in a std::string * @param url The URL to download * @return The download result */ std::string download(const std::string& url); private: void* curl; }; #endif /* HTTPDOWNLOADER_HPP */
以下是源代码:
/** * HTTPDownloader.cpp * * A simple C++ wrapper for the libcurl easy API. * * Written by Uli Köhler (techoverflow.net) * Published under CC0 1.0 Universal (public domain) */ #include "HTTPDownloader.hpp" #include <curl/curl.h> #include <curl/easy.h> #include <curl/curlbuild.h> #include <sstream> #include <iostream> using namespace std; size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) { string data((const char*) ptr, (size_t) size * nmemb); *((stringstream*) stream) << data; return size * nmemb; } HTTPDownloader::HTTPDownloader() { curl = curl_easy_init(); } HTTPDownloader::~HTTPDownloader() { curl_easy_cleanup(curl); } string HTTPDownloader::download(const std::string& url) { curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); /* example.com is redirected, so we tell libcurl to follow redirection */ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); //Prevent "longjmp causes uninitialized stack frame" bug curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "deflate"); std::stringstream out; curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &out); /* Perform the request, res will get the return code */ CURLcode res = curl_easy_perform(curl); /* Check for errors */ if (res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } return out.str(); }
使用“新”C ++ 11 lambdafunction,这可以在几行代码中完成。
std::string resultBody { }; curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resultBody); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, static_cast<size_t (__stdcall *)(char*, size_t, size_t, void*)>( [](char* ptr, size_t size, size_t nmemb, void* resultBody){ *(static_cast<std::string*>(resultBody)) += std::string {ptr, size * nmemb}; return size * nmemb; } )); CURLcode curlResult = curl_easy_perform(curl); std::cout << "RESULT BODY:\n" << resultBody << std::endl; // Cleanup etc
注意__stdcall强制转换符合C调用约定(cURL是一个C库)