C libcurl mendapatkan keluaran menjadi sebuah string

98

Saya ingin menyimpan hasil dari fungsi curl ini dalam sebuah variabel, bagaimana caranya?

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

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

  curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "curl.haxx.se");
    res = curl_easy_perform(curl);

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

terima kasih, saya menyelesaikannya seperti ini:

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

function_pt(void *ptr, size_t size, size_t nmemb, void *stream){
    printf("%d", atoi(ptr));
}

int main(void)
{
  CURL *curl;
  curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "curl.haxx.se");
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, function_pt);
    curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
  system("pause");
  return 0;
}
frx08
sumber
1
Hanya untuk menunjukkan dalam solusi Anda di function_pt () Anda mengubah string di ptr menjadi integer untuk mengubahnya kembali menjadi string di output. Anda dapat mengeluarkan string secara langsung (dan melihat respons lengkapnya).
zzz
2
berikut ini tautan ke contoh cURL curl.haxx.se/libcurl/c/getinmemory.html
lafferc
1
CURLcode res;tidak digunakan
fnc12
1
pertanyaan yang sama tetapi untuk C ++, bukan c, buka di sini: Simpan hasil konten cURL menjadi string di C ++
Trevor Boyd Smith

Jawaban:

117

Anda dapat mengatur fungsi panggilan balik untuk menerima potongan data yang masuk menggunakan curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, myfunc);

Callback akan mengambil argumen yang ditentukan pengguna yang dapat Anda setel menggunakan curl_easy_setopt(curl, CURLOPT_WRITEDATA, p)

Berikut adalah cuplikan kode yang meneruskan buffer struct string {*ptr; len}ke fungsi callback dan mengembangkan buffer tersebut pada setiap panggilan menggunakan realloc ().

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

struct string {
  char *ptr;
  size_t len;
};

void init_string(struct string *s) {
  s->len = 0;
  s->ptr = malloc(s->len+1);
  if (s->ptr == NULL) {
    fprintf(stderr, "malloc() failed\n");
    exit(EXIT_FAILURE);
  }
  s->ptr[0] = '\0';
}

size_t writefunc(void *ptr, size_t size, size_t nmemb, struct string *s)
{
  size_t new_len = s->len + size*nmemb;
  s->ptr = realloc(s->ptr, new_len+1);
  if (s->ptr == NULL) {
    fprintf(stderr, "realloc() failed\n");
    exit(EXIT_FAILURE);
  }
  memcpy(s->ptr+s->len, ptr, size*nmemb);
  s->ptr[new_len] = '\0';
  s->len = new_len;

  return size*nmemb;
}

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

  curl = curl_easy_init();
  if(curl) {
    struct string s;
    init_string(&s);

    curl_easy_setopt(curl, CURLOPT_URL, "curl.haxx.se");
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
    res = curl_easy_perform(curl);

    printf("%s\n", s.ptr);
    free(s.ptr);

    /* always cleanup */
    curl_easy_cleanup(curl);
  }
  return 0;
}
Alex Jasmin
sumber
1
Bagus. Bahkan lebih bagus jika semua itu size_t(selain lendirinya sendiri) akan dideklarasikan const.
alk
2
untuk C ++ std::stringbuka di sini
Trevor Boyd Smith
35

Jawaban berikut adalah C ++ cara untuk melakukannya, dengan std::string, sebagai ganti string yang diakhiri dengan null. Ini masih menggunakan fungsi panggilan balik (tidak ada jalan lain), tetapi juga menangani kesalahan alokasi menggunakan coba / tangkap.

#include <iostream>
#include <string>
#include <curl/curl.h>

size_t CurlWrite_CallbackFunc_StdString(void *contents, size_t size, size_t nmemb, std::string *s)
{
    size_t newLength = size*nmemb;
    try
    {
        s->append((char*)contents, newLength);
    }
    catch(std::bad_alloc &e)
    {
        //handle memory problem
        return 0;
    }
    return newLength;
}
int main()
{
    CURL *curl;
    CURLcode res;

    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();
    std::string s;
    if(curl)
    {

        curl_easy_setopt(curl, CURLOPT_URL, "curl.haxx.se");

        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); //only for https
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); //only for https
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWrite_CallbackFunc_StdString);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
        curl_easy_setopt (curl, CURLOPT_VERBOSE, 1L); //remove this to disable verbose output


        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);
        /* Check for errors */
        if(res != CURLE_OK)
        {
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
                    curl_easy_strerror(res));
        }

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

    std::cout<<s<<std::endl;

    std::cout<< "Program finished!" << std::endl;
}
Fisikawan Kuantum
sumber
Saya pikir std :: string :: append dapat membuat fungsi panggilan balik itu jauh lebih sederhana.
Ryan Burn
@rickb Anda benar; s->append((char*)contents. nmemb);bekerja dengan sempurna dengan saya dan lebih ringkas. Selain itu, tanda tangan fungsi resmi untuk callback memiliki char*argumen sebagai pertama, jadi Anda bisa menggunakannya dan menghilangkan casting. Dan terakhir, s->resize()menginisialisasi ruang yang baru dialokasikan. Saat Anda akan menimpanya, s->reserve()akan lebih efisien.
Jeinzi
Ini sangat membantu saya. Bisakah Anda juga memberikan contoh bagaimana melakukannya dengan HTTP POST :-)
Lord Wolfenstein
9

Dari membaca manual di sini: http://curl.haxx.se/libcurl/c/curl_easy_setopt.html Saya rasa Anda perlu beberapa panggilan ke CURL_SETOPT, yang pertama adalah URL yang ingin Anda proses, yang kedua adalah seperti:

curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, function_ptr);

Di mana function_ptr cocok dengan tanda tangan ini:

size_t function( void *ptr, size_t size, size_t nmemb, void *stream)

Apa yang terjadi di sini adalah Anda menunjukkan fungsi panggilan balik yang akan dipanggil oleh libcurl ketika ia memiliki beberapa keluaran untuk ditulis dari transfer apa pun yang Anda panggil. Anda bisa membuatnya untuk secara otomatis menulis ke file, atau memberikan pointer ke fungsi yang akan menangani output itu sendiri. Dengan menggunakan fungsi ini, Anda harus dapat merakit berbagai string keluaran menjadi satu bagian dan kemudian menggunakannya dalam program Anda.

Saya tidak yakin opsi lain apa yang mungkin harus Anda setel / apa lagi yang memengaruhi perilaku aplikasi yang Anda inginkan, jadi lihat baik-baik halaman itu.


sumber
0

Inilah rasa C ++ dari jawaban yang diterima dari alex-jasmin

#include <iostream>
#include <string>
#include <curl/curl.h>

size_t writefunc(void *ptr, size_t size, size_t nmemb, std::string *s) 
{
  s->append(static_cast<char *>(ptr), size*nmemb);
  return size*nmemb;
}

int main(void)
{
  CURL *curl = curl_easy_init();
  if (curl)
  {
    std::string s;

    curl_easy_setopt(curl, CURLOPT_URL, "curl.haxx.se");
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);

    CURLcode res = curl_easy_perform(curl);

    std::cout << s << std::endl;

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

Paul Grinberg
sumber