web-dev-qa-db-fra.com

C libcurl obtenir la sortie dans une chaîne

Je veux stocker le résultat de cette fonction curl dans une variable, comment puis-je le faire?

#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;
}

merci, je l'ai résolu comme ça:

#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;
}
81
frx08

Vous pouvez définir une fonction de rappel pour recevoir les fragments de données entrants à l'aide de curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, myfunc);

Le rappel utilisera un argument défini par l'utilisateur que vous pouvez définir à l'aide de curl_easy_setopt(curl, CURLOPT_WRITEDATA, p)

Voici un extrait de code qui passe un tampon struct string {*ptr; len} à la fonction de rappel et augmente ce tampon à chaque appel en utilisant 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;
}
100
Alex Jasmin

La réponse suivante est la manière de faire C++, avec std::string, au lieu d'une chaîne terminée par un caractère nul. Il utilise toujours une fonction de rappel (il n'y a aucun moyen de le contourner), mais gère également les erreurs d'allocation à l'aide de try/catch.

#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;
}
27

De la lecture du manuel ici: http://curl.haxx.se/libcurl/c/curl_easy_setopt.html Je pense que vous avez besoin de plusieurs appels à CURL_SETOPT, le premier étant l'URL que vous souhaitez traiter, le la seconde étant quelque chose comme:

curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, function_ptr);

Où function_ptr correspond à cette signature:

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

Ce qui se passe ici, c'est que vous dénommez une fonction de rappel que libcurl appellera quand il aura une sortie à écrire à partir du transfert que vous avez appelé. Vous pouvez le faire écrire automatiquement dans un fichier ou lui transmettre un pointeur vers une fonction qui gérera la sortie elle-même. En utilisant cette fonction, vous devriez être capable d'assembler les différentes chaînes de sortie en un seul morceau, puis de les utiliser dans votre programme.

Je ne sais pas quelles autres options vous pouvez définir/quels autres facteurs affectent la manière dont vous souhaitez que votre application se comporte. Consultez donc cette page.

7
user257111