C语言模仿post请求并解析返回的json字符串
json
适用于现代 C++ 的 JSON。
项目地址:https://gitcode.com/gh_mirrors/js/json
免费下载资源
·
C语言模仿post请求并解析返回的json字符串
1. 需求
最近有一个需求,需要C语言判断某个域名是否备案,并爬取页面内容,过滤是否存在某个关键字;需求是很简单,可是用C语言如何实现呢?废话不多说,直接展示代码(已测试)
2. C语言代码实现
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <curl/curl.h>
#include <curl/easy.h>
#include <string.h>
#include <json/json.h>
#include <iconv.h>
struct MemoryStruct
{
char *memory;
size_t size;
};
//字符集转换核心函数,必须手动包含头文件
int code_convert(char *from_charset,char *to_charset,char *inbuf,size_t inlen,char *outbuf,size_t outlen){
iconv_t cd;
int rc;
char **pin = &inbuf;
char **pout = &outbuf;
cd = iconv_open(to_charset,from_charset);
if(cd==(iconv_t) -1){
printf("字符集打开失败\n");
return -1;
}
memset(outbuf,0,outlen);
if(iconv(cd,pin,&inlen,pout,&outlen)==-1){
//changlq change 20160606
iconv_close(cd);
return -1;
}
iconv_close(cd);
return 0;
}
//gbk->utf8对外接口, #以后必须把字符及定义为宏变量
int g2u(char *inbuf,char *outbuf){
return code_convert("gbk","utf8",inbuf,(size_t)strlen(inbuf),outbuf,(size_t)(strlen(inbuf)*4));
}
//解析json格式数据,//code:0-已备案,请求执行成功;1-未备案,请求执行失败
int print_json_str( char *_json_str ){
//json解析{"code":"0","msg":"success","data":{"name":"test","sex":"man"}}
char *json_msg=_json_str;
printf("changlq_test:[%s]\n",json_msg);
struct json_object *result_json=NULL;
struct json_object *tmp_obj=NULL;
result_json = json_tokener_parse(json_msg);
json_object_object_get_ex(result_json, "code",&tmp_obj);
int _code = json_object_get_int(tmp_obj); //0-已备案,请求执行成功;1-未备案,请求执行失败
/* 已将所有参数解析,但此处仅展示code返回码,如需使用其它参数,打开此处注释即可
if (_code == 0) {
json_object_object_get_ex(result_json, "msg",&tmp_obj);
const char *_msg = json_object_get_string(tmp_obj);
json_object_object_get_ex(result_json, "data",&tmp_obj);
struct json_object *_tmp_obj=NULL;
json_object_object_get_ex(tmp_obj, "name",&_tmp_obj);
const char *data_name = json_object_get_string(_tmp_obj);
json_object_object_get_ex(tmp_obj, "sex",&_tmp_obj);
const char *data_sex = json_object_get_string(_tmp_obj);
printf("code[%d] msg[%s] data.name[%s] data.sex[%s]\n", _code, _msg, data_name,data_sex);
}
*/
//20200326 changlq add 内存泄漏相关排查(valgrind)
json_object_put(result_json);
json_object_put(tmp_obj);
return _code;
}
//curl回调函数,由于访问一次可能调用多次回调函数,所以此处需要拼接字符串
size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
{
//一次返回可能对应多次调用,此处用于拼接完整版的返回信息
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)data;
mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);
if (mem->memory)
{
memcpy(&(mem->memory[mem->size]), ptr, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
}
return realsize;
}
//模仿post请求,传入端口用于拼接url,调用php接口时使用(需要传递的参数按格式拼接好后,调用curl_easy_setopt(pCurl, CURLOPT_POSTFIELDS, sp_para)设置即可)
//返回接口调用状态,即php-api函数的执行情况//0-已备案,请求执行成功;1-未备案,请求执行失败
//传入参数:php服务器ip 通信端口 相对路径uri 需要传输给php的参数(以按照格式拼接完成)
int send_post(char *sp_ip,int sp_port,char *sp_path,char *sp_para){
//拼接url
char *full_url=(char *)malloc(2048);
memset(full_url,0x0,2048);
if( sp_port==443 ){ //https
sprintf(full_url,"https://%s:%d/%s",sp_ip,sp_port,sp_path);
}else{ //默认http
sprintf(full_url,"http://%s:%d/%s",sp_ip,sp_port,sp_path);
}
printf("post_url:[%s]\n",full_url);
CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
if(CURLE_OK != res)
{
printf("curl init failed\n");
return -1;
}
CURL *pCurl = NULL;
pCurl = curl_easy_init();
if( NULL == pCurl)
{
printf("Init CURL failed...\n");
curl_global_cleanup();
return -1;
}
//请求的url地址
curl_easy_setopt(pCurl, CURLOPT_URL, full_url ); //需要获取的URL地址
//post方式发送请求不设置的话默认使用get方法发送请求
curl_easy_setopt(pCurl, CURLOPT_POST, 1);
//post请求参数设置,get方法的参数可以在url中体现,post的参数必须在此处设置,参数格式如下"name=daniel&project=curl"
curl_easy_setopt(pCurl, CURLOPT_POSTFIELDS, sp_para);
// https请求 不验证证书和hosts
curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0);
//请求超时时长(秒)
curl_easy_setopt(pCurl, CURLOPT_TIMEOUT, 3L);
//设置连接超时时长(秒)
curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT, 10L);
//调用过程中输出更多的关于调用操作的详细信息(屏幕输出)
// curl_easy_setopt(pCurl, CURLOPT_VERBOSE, 1L); //启用时会汇报所有的信息
//传递调用完成时的回调函数
curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); //得到请求结果后的回调函数
struct MemoryStruct oDataChunk; //请求结果的保存格式
oDataChunk.memory=(char *)malloc(1);
oDataChunk.size=0;
//回调函数第四个参数
curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, &oDataChunk);
//允许URL地址的重定向
curl_easy_setopt(pCurl, CURLOPT_FOLLOWLOCATION, 1L);//允许重定向
//告诉libcurl在输出请求体时包含头部信息
curl_easy_setopt(pCurl, CURLOPT_HEADER, 0L);
//关闭中断信号响应,如果是多线程,请将该参数置为1。这个选项用于unix环境下的多线程应用仍然可以使用各种timeout选项,而不会引发信号中断致使程序退出。
curl_easy_setopt(pCurl, CURLOPT_NOSIGNAL, 1L);
struct curl_slist *pList = NULL;
/* 缺省的头信息 */
pList = curl_slist_append(pList,"User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12");
pList = curl_slist_append(pList,"Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
pList = curl_slist_append(pList,"Accept-language: zh-cn,zh;q=0.5");
pList = curl_slist_append(pList,"Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7");
//使用模拟的header头设置HTTP请求的头信息
curl_easy_setopt(pCurl, CURLOPT_HTTPHEADER, pList);
//用于执行CURL对象,是一个阻塞类型的操作
res=-1;
res = curl_easy_perform(pCurl); //执行请求
if( res != CURLE_OK ){ //curl_easy_perform执行失败
printf("curl_easy_perform error,err_msg:[%ld]\n",res);
}
long res_code=-1;
res=-1;
res=curl_easy_getinfo(pCurl, CURLINFO_RESPONSE_CODE, &res_code);
//正确响应后,请求转写成本地文件的文件
int ret_flag=-1;
if( res == CURLE_OK )
{
if( res_code == 200 || res_code == 201 ){
ret_flag=print_json_str(oDataChunk.memory);
}
}
free(oDataChunk.memory);
free(full_url);
curl_slist_free_all(pList);
curl_easy_cleanup(pCurl);
curl_global_cleanup();
return ret_flag;
}
//模仿get请求,传入端口用于判断http还是https,不用于拼接url,爬去页面时使用(需要传递的参数按照格式拼接到url后面即可)
//返回是否返现关键字//0-发现关键字;1-未发现
//传入参数:需要爬取的url 目标端口 关键字
int send_get(char *sg_domain_uri,int sg_port,char *sg_key_word){
//拼接url
char *full_url=(char *)malloc(2048);
memset(full_url,0x0,2048);
if( sg_port==443 ){ //https
sprintf(full_url,"https://%s",sg_domain_uri);
}else{ //默认http
sprintf(full_url,"http://%s",sg_domain_uri);
}
printf("get_url:[%s]\n",full_url);
CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
if(CURLE_OK != res)
{
printf("curl init failed\n");
return -1;
}
CURL *pCurl = NULL;
pCurl = curl_easy_init();
if( NULL == pCurl)
{
printf("Init CURL failed...\n");
curl_global_cleanup();
return -1;
}
//请求的url地址
curl_easy_setopt(pCurl, CURLOPT_URL, full_url ); //需要获取的URL地址
//post方式发送请求不设置的话默认使用get方法发送请求
// curl_easy_setopt(pCurl, CURLOPT_POST, 1);
//post请求参数设置,get方法的参数可以在url中体现,post的参数必须在此处设置,参数格式如下"name=daniel&project=curl"
// curl_easy_setopt(pCurl, CURLOPT_POSTFIELDS, sp_para);
// https请求 不验证证书和hosts
curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0);
//请求超时时长(秒)
curl_easy_setopt(pCurl, CURLOPT_TIMEOUT, 3L);
//设置连接超时时长(秒)
curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT, 10L);
//调用过程中输出更多的关于调用操作的详细信息(屏幕输出)
// curl_easy_setopt(pCurl, CURLOPT_VERBOSE, 1L); //启用时会汇报所有的信息
//传递调用完成时的回调函数
curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); //得到请求结果后的回调函数
struct MemoryStruct oDataChunk; //请求结果的保存格式
oDataChunk.memory=(char *)malloc(1);
oDataChunk.size=0;
//回调函数第四个参数
curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, &oDataChunk);
//允许URL地址的重定向
// curl_easy_setopt(pCurl, CURLOPT_FOLLOWLOCATION, 1L);//允许重定向
//告诉libcurl在输出请求体时包含头部信息
// curl_easy_setopt(pCurl, CURLOPT_HEADER, 0L);
//关闭中断信号响应,如果是多线程,请将该参数置为1。这个选项用于unix环境下的多线程应用仍然可以使用各种timeout选项,而不会引发信号中断致使程序退出。
curl_easy_setopt(pCurl, CURLOPT_NOSIGNAL, 1L);
struct curl_slist *pList = NULL;
/* 缺省的头信息 */
pList = curl_slist_append(pList,"User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12");
pList = curl_slist_append(pList,"Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
pList = curl_slist_append(pList,"Accept-language: zh-cn,zh;q=0.5");
pList = curl_slist_append(pList,"Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7");
//使用模拟的header头设置HTTP请求的头信息
curl_easy_setopt(pCurl, CURLOPT_HTTPHEADER, pList);
//用于执行CURL对象,是一个阻塞类型的操作
res=-1;
res = curl_easy_perform(pCurl); //执行请求
if( res != CURLE_OK ){ //curl_easy_perform执行失败
printf("curl_easy_perform error,err_msg:[%ld]\n",res);
}
long res_code=-1;
res=-1;
res=curl_easy_getinfo(pCurl, CURLINFO_RESPONSE_CODE, &res_code);
//正确响应后,请求转写成本地文件的文件
int ret_flag=-1;
if( res == CURLE_OK )
{
if( res_code == 200 || res_code == 201 ){
//printf("changlq_get:[%s]\n",oDataChunk.memory);
//页面内容爬取到oDataChunk.memory变量之后需要做如下操作
//0.统一变量和关键字编码格式,然后过滤关键字
char in_str[100],out_str[400];
memset(in_str,0x0,sizeof(in_str));
memset(out_str,0x0,sizeof(out_str));
strcpy(in_str,sg_key_word);
int rc=g2u(in_str,out_str);
if(rc == 0){
//1.根据关键字过滤网页
if(strstr(oDataChunk.memory,out_str)){
//printf("data_test:[%s]\n",oDataChunk.memory);
printf("found keyword\n");
ret_flag=0;//发现关键字
//2.如果页面存在关键字,需要将页面内容以utf8的格式存储到数据库中,并返回存在标志
}else{
printf("not found\n");
ret_flag=1;//没有发现关键字,此处默认网页的字符集和库的都是utf8,如果后续需要判断的话,建议将关键字转为gbk再过滤一遍
}
}else{
printf("iconv error\n");
}
/*
//1.无需转码,根据关键字过滤网页
if(strstr(oDataChunk.memory,sg_key_word)){
//printf("data_test:[%s]\n",oDataChunk.memory);
printf("found keyword\n");
ret_flag=0;//发现关键字
//2.如果页面存在关键字,需要将页面内容以utf8的格式存储到数据库中,并返回存在标志
}else{
printf("not found\n");
ret_flag=1;//没有发现关键字,此处默认网页的字符集和库的都是utf8,如果后续需要判断的话,建议将关键字转为gbk再过滤一遍
}
*/
}
}
free(oDataChunk.memory);
free(full_url);
curl_slist_free_all(pList);
curl_easy_cleanup(pCurl);
curl_global_cleanup();
return ret_flag;
}
//gcc send_get_msg.c -o send_get_msg -lcurl -ljson
int main()
{
//查询是否备案的php接口:http://192.168.9.168:80/index.php,需要出入参数domain (此接口为模拟接口,非正式接口)
char ip[255] = "192.168.9.168";
int port=80;
char para[255] = "domain=www.baidu.com";
//查询域名是否备案
int ret_flag=send_post(ip,port,"index.php",para);
if(ret_flag==0){
printf("已备案\n");
}else{
printf("未备案\n");
}
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
//爬取www.baidu.com,并判断页面中是否有“百度”关键字(由于我本地用的是GBK,而浏览器是utf-8字符集,所以过滤关键字的时候我增加了转码字符串的动作,即将第三个参数“百度”字符串由GBK转为UTF-8,如果本地就是utf-8的,无需后续转码,两种方式都已给出)
send_get("www.baidu.com",443,"百度");
return 0;
}
效果展示:
GitHub 加速计划 / js / json
41.72 K
6.61 K
下载
适用于现代 C++ 的 JSON。
最近提交(Master分支:1 个月前 )
960b763e
3 个月前
8c391e04
6 个月前
更多推荐
已为社区贡献1条内容
所有评论(0)