2010-11-19 37 views
2

J'essaie d'inclure cette fonction curl dans ma classe mais j'ai des problèmes avec CURLOPT_WRITEFUNCTION. Après la compilation ne m'a pas trouvé une solution. J'ai également essayé certaines choses basées sur stackoverflow à non disponibles.CURLOPT_WRITEFUNCTION pointeur vers la fonction membre

Voilà ma tentative (remplacer le terme 'écrivain' dans ce code)

noeud

:: écrivain & noeud :: écrivain std :: bind1st (std :: mem_fun (& noeud :: écrivain), ce) ;

Voici mon code:

#ifndef NODE_H_ 
#define NODE_H_ 

int writer(char *data, std::size_t size, std::size_t nmemb, std::string *buffer); 

/* 
* function prototypes 
*/ 

class node { 
/* 
    * general struct to hold html element properties 
    */ 
struct tag; 

/* 
    * the url and source of the page 
    */ 
std::string url; 
std::string source; 

/* 
    * vector of structures that store tag elements 
    */ 
std::vector<tag> heading; 
std::vector<tag> anchor; 

/* 
    * grab source with curl 
    */ 
std::string curlHttpget(const std::string &url); 

/* 
    * add tag structs to vector 
    * @see std::vector<tag> heading 
    * @see std::vector<tag> anchor 
    */ 
void add_heading(std::string, std::string); 
void add_anchor(std::string, std::string); 

public: 
/* 
    * constructors 
    */ 
node(){} 
node(std::string); 

/* 
    * deconstructors 
    */ 
~node(){} 

/* 
    * crawl page 
    */ 
void load(std::string seed);//crawls the page 

/* 
    * anchor tags 
    */ 
void get_anchors();// scrape the anchor tags 
void display_anchors(); 

/* 
    * heading tags 
    */ 
void get_headings();// scrape heading tags 
void display_headings(); 
}; 
/* 
* for all stored html elements 
*/ 
struct node::tag { 
std::string text; 
std::string properties; 
tag(std::string t, std::string p) : text(t), properties(p) {} 
}; 

/* 
* constructors 
*/ 
node::node(std::string seed) { 
load(seed); 
get_anchors(); 
get_headings(); 
} 
/* 
* araneus::subroutines 
*/ 

// crawl the page 
void node::load(std::string seed) { 
url = seed; 
source = curlHttpget(url); 
} 


//scrape html source 
std::string node::curlHttpget(const std::string &url) { 
std::string buffer; 

CURL *curl; 
CURLcode result; 

curl = curl_easy_init(); 

if (curl) { 
    curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); 
    curl_easy_setopt(curl, CURLOPT_HEADER, 0); 
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer); 
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer); 

    result = curl_easy_perform(curl);//http get performed 

    curl_easy_cleanup(curl);//must cleanup 

    //error codes: http://curl.haxx.se/libcurl/c/libcurl-errors.html 
    if (result == CURLE_OK) { 
    return buffer; 
    } 
    //curl_easy_strerror was added in libcurl 7.12.0 
    std::cerr << "error: " << result << " " << curl_easy_strerror(result) << std::endl; 
    return ""; 
} 

std::cerr << "error: could not initalize curl" << std::endl; 
return ""; 
} 

void node::get_headings() { 
static const regex expression("<[hH][1-6]\\s*(?<properties>.*?)\\s*>(?<name>.*?)</\\s*[hH][1-6]\\s*>"); 

int const subMatches[] = { 1, 2 }; 

sregex_token_iterator p(source.begin(), source.end(), expression, subMatches); 
sregex_token_iterator end; 

string text; 
string properties; 

int count = 0; 
for (;p != end; count++, ++p) 
{ 
    string m(p->first, p->second); 

    if(count % 2) { 
    text = m; 
    add_heading(text, properties); 
    } 
    else { 
    properties = m; 
    } 
} 
} 

//use regex to find anchors in source 
void node::get_anchors() { 
static const regex expression("<[a|A].*?[href|HREF]\\s*=[\"\"'](?<url>.*?)[\"\"'].*?>(?<name>.*?)</[a|A]>"); 
static const regex relative("^\\/"); 
static const regex firstChar("^[A-Za-z0-9\\-_\\$\\.\\+!\\*'\\(\\)#]"); // valid url characters 
static const regex protocol("^[http:\\/\\/|HTTP:\\/\\/|https:\\/\\/|HTTPS:\\/\\/|ftp:\\/\\/|FTP:\\/\\/|sftp:\\/\\/|SFTP:\\/\\/]"); 

int const subMatches[] = { 1, 2 }; 

sregex_token_iterator p(source.begin(), source.end(), expression, subMatches); 
sregex_token_iterator end; 

string text, properties; 

int count = 0; 
for (; p != end; count++, ++p) { 
    std::string m(p->first, p->second); 

    if(count % 2) { 
    text = m; 
    add_anchor(text, properties); 
    } 
    else { 
    if(regex_search(m, relative)) { //if link is in "/somewhere" format 
    properties = url + m; 
    } 
    else if(regex_search(m, protocol)) { //if link is absolute "http://www.somewhere.com" 
    properties = m; 
    } 
    else if(regex_search(m, firstChar)) { //if link starts with a valid url char "somewhere.html" 
    properties = url + "/" + m; 
    } 
    else { 
    std::cout << "link of unknown protocol: " << m << std::endl; 
    } 
    } 
} 
} 

void node::add_heading(std::string text, std::string properties) { 
heading.push_back(tag(text, properties)); 
} 

void node::display_headings() { 
for(int i = 0; i < (int)heading.size(); i++) { 
    std::cout<< "[h]: " << heading[i].text << endl; 
    std::cout<< "[h.properties]: " << heading[i].properties << endl; 
} 
cout << "found " << (int)heading.size() << " <h[1-6]> tags" << endl; 
} 

void node::add_anchor(std::string text, std::string properties) { 
anchor.push_back(tag(text, properties)); 
} 

void node::display_anchors() { 
for(int i = 0; i < (int)anchor.size(); i++) { 
    std::cout<< "[a]: " << anchor[i].text << endl; 
    std::cout<< "[a.properties]: " << anchor[i].properties << endl; 
} 
cout << "found " << (int)anchor.size() << " <a> tags" << endl; 
} 

//required by libcurl 
int writer(char *data, std::size_t size, std::size_t nmemb, std::string *buffer) { 
int result = 0; 

if (buffer != NULL) { 
    buffer->append(data, size * nmemb); 
    result = size * nmemb; 
} 
return result; 
} 

#endif /* NODE_H_ */ 

à la recherche d'une solution pour obtenir la fonction 'int écrivain' être "noeud int :: écrivain". le problème se produit dans std :: string node :: curlHttpget, lorsque j'appelle CURLOPT_WRITEFUNCTION.

& noeud :: auteur compile, mais donne un défaut seg =/

grâce

Répondre

1

Au lieu d'utiliser std :: string * nœud utilisez * comme le paramètre ou une autre classe comme HttpGet qui a un std: : chaîne et un pointeur vers votre noeud afin qu'il puisse écrire dans la chaîne et accéder à votre noeud à chaque appel.

boost :: bind ne fonctionnera pas pour les rappels C-API.

Il compile parce que curl_easy_setopt utilise ... donc il n'est pas totalement typé. Vous pouvez passer n'importe quel type que vous voulez sous le soleil et il compilera. Il ne fonctionnera probablement pas, comme vous l'avez constaté à vos frais.

J'utiliserais la sécurité de type supplémentaire consistant à faire en sorte que votre fonction ait exactement la même signature que Curl_write_callback, c'est-à-dire void * en tant que 4ème paramètre, et à faire le casting dans l'implémentation de la fonction.