Linux下通过curl实现新浪天气API应用

Linux下通过curl实现新浪天气API应用

新浪天气API的使用方法:

API地址:http://php.weather.sina.com.cn/xml.php?city=%B1%B1%BE%A9&password=DJOYnieT8234jlsK&day=0

红色标记为城市代码(也就是城市的中文转为GB2312的十六进制代码,比如北京对应的GB2312十六进制代码为B1B1BEA9),实际上需要查哪个城市就把红色标记改为对应城市代码即可.而实际上打开此url后对应的是一个xml文件,里面包括了此城市的天气信息.

<?xml version="1.0" encoding="UTF-8"?>
<!-- published at 2014-10-31 17:08:03 -->
<Profiles>
<Weather>
<city>北京</city>
<status1>小雨</status1>
<status2>多云</status2>
<figure1>xiaoyu</figure1>
<figure2>duoyun</figure2>
<direction1>无持续风向</direction1>
<direction2>无持续风向</direction2>
<power1>3</power1>
<power2>3</power2>
<temperature1>14</temperature1>
<temperature2>9</temperature2>
<ssd>5</ssd>
<tgd1>16</tgd1>
<tgd2>16</tgd2>
<zwx>2</zwx>
<ktk>6</ktk>
<pollution>3</pollution>
<xcz></xcz>
<zho></zho>
<diy></diy>
<fas></fas>
<chy>4</chy>
<zho_shuoming>暂无</zho_shuoming>
<diy_shuoming>暂无</diy_shuoming>
<fas_shuoming>暂无</fas_shuoming>
<chy_shuoming>套装、夹衣、风衣、夹克衫、西服套装、马甲衬衫配长裤</chy_shuoming>
<pollution_l>轻度</pollution_l>
<zwx_l></zwx_l>
<ssd_l>略凉</ssd_l>
<fas_l>暂无</fas_l>
<zho_l>暂无</zho_l>
<chy_l>夹衣类</chy_l>
<ktk_l>适宜开启(制热)</ktk_l>
<xcz_l>暂无</xcz_l>
<diy_l>暂无</diy_l>
<pollution_s>对空气污染物扩散无明显影响</pollution_s>
<zwx_s>紫外线弱</zwx_s>
<ssd_s>感觉有些凉,但是凉意微薄,不影响户外活动的开展。</ssd_s>
<ktk_s>适宜开启空调</ktk_s>
<xcz_s>暂无</xcz_s>
<gm>2</gm>
<gm_l>易发期</gm_l>
<gm_s>天气很凉,季节转换的气候,慎重增加衣服;较易引起感冒;</gm_s>
<yd>5</yd>
<yd_l>不适宜</yd_l>
<yd_s>虽然晴空万里,但是天气较凉,多数人不适宜户外运动;</yd_s>
<savedate_weather>2014-10-31</savedate_weather>
<savedate_life>2014-10-31</savedate_life>
<savedate_zhishu>2014-10-31</savedate_zhishu>
</Weather>
</Profiles>

现在我们的工作就是使用curl打开这个xml文件并且将其转换为我们需要的数据结构.

#ifndef __SINA_WEATHER__
#define __SINA_WEATHER__

#include <stdio.h>

#define FALSE (0)
#define TRUE (!0)

#define SINA_WEATHER_URL_HEAD "http://php.weather.sina.com.cn/xml.php?city="
#define SINA_WEATHER_URL_TAIL "&password=DJOYnieT8234jlsK&day=0"

struct date {
    short year;
    short month;
    short day;
};

struct weather_info {
    char * city;

    //天气情况(中文)
    char * status1;
    char * status2;

    //天气情况(拼音)
    char * figure1;
    char * figure2;

    //风向
    char * direction1;
    char * direction2;

    //风级
    char * power1;
    char * power2;

    //温度
    int temperature1;
    int temperature2;

    //体感指数数值
    int ssd;
    //体感度指数
    char * ssd_l;
    //体感度指数说明
    char * ssd_s;

    //体感温度
    int tgd1;
    int tgd2;

    //紫外线指数数值
    int zwx;
    //紫外线指数
    char * zwx_l;
    //紫外线指数说明
    char * zwx_s;

    //空调指数数值
    int ktk;
    //空调指数
    char * ktk_l;
    //空调指数说明
    char * ktk_s;

    //污染指数数值
    int pollution;
    //污染扩散条件
    char * pollution_l;
    //污染指数说明
    char * pollution_s;

    //穿衣指数数值
    int chy;
    //穿衣指数
    char * chy_l;
    //穿衣说明
    char * chy_shuoming;

    //洗车指数数值
    int xcz;
    //洗车指数
    char * xcz_l;
    //洗车指数说明
    char * xcz_s;


    //感冒指数数值
    int gm;
    //感冒指数
    char * gm_l;
    //感冒指数说明
    char * gm_s;

    //运动指数数值
    int yd;
    //运动指数
    char * yd_l;
    //运动指数说明
    char * yd_s;

    struct date weather_date;
    struct date life_date;
    struct date zhishu_date;
};

struct weather_info * get_weather_info_from_sina (const char * city_name);

#endif

先说一下流程,首先设计想法是就定义一个接口,调用时只需要输入一个城市名称,则自动返回此城市的天气信息结构体,而在内部,分别执行了UTF-8转GB2312格式, curl初始化, 获取天气XML信息, 填充struct weather_info结构体.

流程图:
在这里插入图片描述
代码(sina_weather.c):

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

#include "sina_weather.h"
//根据key获取xml中对应的值
char * get_xml_key_value (const char * xml, char * key)
{
    char * head;
    char * tail;
    char stamp[1024];
    char * value;

    sprintf(stamp, "<%s>", key);
    if ((head = strstr (xml, stamp)) == NULL)
        return NULL;

    head = head + strlen (stamp);
    while (isspace (head[0]))
        head ++;

    sprintf(stamp, "</%s>", key);

    if ((tail = strstr (head, stamp)) == NULL)
        return NULL;

    while (isspace(tail[-1]) && (tail > head))
        tail --;

    if (tail > head){
        value = calloc (tail - head + 1, 1);
        memcpy (value, head, tail - head);
        value[tail - head] = 0x00;
    }

    return value;
}
//UTF-8转GB2312
int utf8_to_gb2312 (const char * src, char * dest_buf)
{
    iconv_t con;
    int src_length = strlen (src);

    if( (con = iconv_open ("gb2312", "utf-8")) ==0 )
          return FALSE;

    memset (dest_buf, 0, src_length);

    if(-1 == iconv (con, &src, &src_length, &dest_buf, &src_length))
         return FALSE;
    iconv_close (con);

    return TRUE;
}
//将一个GB2312字符串转换为它的十六进制字符串(每个字符用%隔开)
char * str_convert_to_gb2312_hex (const char * src)
{
    if (src == NULL)
        return NULL;

    int length = strlen (src) - 2;
    int index = 0;
    int num = 0;
    char * gb_str = calloc (((length) + 1), 1);
    char * hex_str = calloc ((length * 3) + 1, 1);

    utf8_to_gb2312 (src, gb_str);
    while ((index / 3) < length) {
        hex_str[index] = '%';
        sprintf (&hex_str[index + 1], "%02X", gb_str[index / 3] & 0xff);
        index = index + 3;
    }
    hex_str[length * 3] = '\0';
    return hex_str;
}

void convert_to_gb2312_clean (char * str)
{
    free (str);
}
//curl下载时的回调函数,当下载到数据时会调用此函数进行操作
size_t down_data_callback (void * ptr, size_t size, size_t nmemb, void * user_buf)
{
    strcat (user_buf, ptr);
    return size * nmemb;
}

uint64_t curl_get_content (const char * url, char * content)
{
    if ((url == NULL) || (content == NULL))
        return;

    CURL * curl = curl_easy_init ();
    curl_easy_setopt (curl, CURLOPT_URL, url);                               //设置curl的目标url地址
    curl_easy_setopt (curl, CURLOPT_TIMEOUT, 15);                            //下载超时时间
    curl_easy_setopt (curl, CURLOPT_NOSIGNAL, 1);                            //屏蔽其他信号
    curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, down_data_callback);      //设置下载回调函数
    curl_easy_setopt (curl, CURLOPT_WRITEDATA, content);                     //设置下载数据保存缓冲区(此参数会传到down_data_callback的user_buf)

    CURLcode retval = curl_easy_perform (curl);
    if (retval == CURLE_OK) {
        double down_length = 0;
        curl_easy_getinfo (curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &down_length);
        curl_easy_cleanup (curl);
        return (uint64_t)down_length;
    }
    curl_easy_cleanup (curl);
    return 0;
}

struct weather_info * weather_info_get_from_xml (const char * xml, struct weather_info * w_info)
{
    if ((xml == NULL) || (w_info == NULL))
        return w_info;

    char * str_data = NULL;

    w_info->city = get_xml_key_value (xml, "city");
    w_info->status1 = get_xml_key_value (xml, "status1");
    w_info->status1 = get_xml_key_value (xml, "status1");
    str_data = get_xml_key_value (xml, "temperature1");
    w_info->temperature1 = (int) atoi (str_data);
    free (str_data);
    str_data = get_xml_key_value (xml, "temperature2");
    w_info->temperature2 = (int) atoi (str_data);
    free (str_data);  //此处省略N多,基本都同上操作.
}

struct weather_info * get_weather_info_from_sina (const char * city_name)
{
    if (city_name == NULL)
        return NULL;

    CURL * curl = NULL;
    CURLcode retval = 0;
    char xml_data[4096];
    char url[1024] = SINA_WEATHER_URL_HEAD;
    char * city_hex = str_convert_to_gb2312_hex (city_name);
    struct weather_info * sina_w_info = calloc (sizeof (struct weather_info), 1);

    strcat (url, city_hex);
    strcat (url, SINA_WEATHER_URL_TAIL);

    convert_to_gb2312_clean (city_hex);

    uint64_t down_size = curl_get_content (url, xml_data);

    if (down_size == 0) {
        free (sina_w_info);
        return NULL;
    }

    weather_info_get_from_xml (xml_data, sina_w_info);
    return sina_w_info;
}

CURL:

或许有些同学不太清楚怎么在c中使用curl库,其实使用的方法很简单,就简单说明一下,在ubuntu下安装curl库命令

apt-get install libcurl-nss-dev

在编译时需要加入的选项:

-lcurl
  使用curl下载时常规的代码顺序为:

CURL * curl = curl_easy_init ();                       //初始化
    curl_easy_setopt (curl, CURLOPT_URL, url);             //具体设置代表的意思在http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
    curl_easy_setopt (curl, CURLOPT_TIMEOUT, 15);
    curl_easy_setopt (curl, CURLOPT_NOSIGNAL, 1);
    curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, down_data_callback);
    curl_easy_setopt (curl, CURLOPT_WRITEDATA, content);
    CURLcode retval = curl_easy_perform (curl);           //执行操作
    if (retval == CURLE_OK) {   
    //添加所需要处理的代码       ........
    }
    curl_easy_cleanup (curl);                             //清空

在使用curl下载时,会设置CURLOPT_WRITEFUNCTION,此设置主要是为了在下载有数据过来时,调用down_data_callback这个回调函数,并将数据保存到content这个缓冲区中.

curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, down_data_callback);
curl_easy_setopt (curl, CURLOPT_WRITEDATA, content);

size_t down_data_callback (void * ptr, size_t size, size_t nmemb, void * user_buf)
{
  strcat (user_buf, ptr);
  return size * nmemb;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值