随笔-341  评论-2670  文章-0  trackbacks-0

在S1死程群@kula的鼓励下,我开始使用kula提供的api来操作那个傻逼的“鸟窝”网站(https://www.niaowo.me)。不过由于我自己在业余时间写的程序都喜欢用C++和Windows API,因此我琢磨了几天,真的让我用C++给写了出来。

我写了一个HttpUtility库来实现C++操作http/https服务的功能,这份代码可以在这里获得:

HttpUtility.h:http://gac.codeplex.com/SourceControl/changeset/view/95641#2295555
HttpUtility.cpp:http://gac.codeplex.com/SourceControl/changeset/view/95641#2295554

使用的时候很简单,只需要HttpRequest里面填满了参数,然后就可以用HttpQuery参数获得一个HttpResponse类型,这个类型里面写满了http服务器的返回值、返回内容和cookie等的数据。譬如说用来post来登陆鸟窝,然后拿到cookie之后查询首页的所有帖子,大概就可以这么写:

WString NestleGetSession(const WString& username, const WString& password, const WString& apiKey, const WString& apiSecret)
{
    WString body=L"api_key="+apiKey+L"&api_secret="+apiSecret+L"&username="+username+L"&password="+password;

    HttpRequest request;
    HttpResponse response;

    request.SetHost(L"https://www.niaowo.me/account/token/");
    request.method=L"POST";
    request.contentType=L"application/x-www-form-urlencoded";
    request.SetBodyUtf8(body);
    HttpQuery(request, response);

    if(response.statusCode==200)
    {
        return response.cookie;
    }
    else
    {
        return L"";
    }
}

WString NestleGetXml(const WString& path, const WString& cookie)
{
    HttpRequest request;
    HttpResponse response;

    request.SetHost(L"https://www.niaowo.me"+path+L".xml");
    request.method=L"GET";
    request.cookie=cookie;
    request.acceptTypes.Add(L"application/xml");
    HttpQuery(request, response);
   

    if(response.statusCode==200)
    {
        return response.GetBodyUtf8();
    }
    else
    {
        return L"";
    }
}

于是我们终于获得了一个保存在vl::WString的xml字符串了,那怎么办呢?这个时候需要出动IXMLDOMDocument2来解析我们的xml。只要装了IE的计算机上都是有IXMLDOMDocument2的,而不装IE的Windows PC是不存在的,因此我们总是可以大胆的使用。当然,用IXMLDOMDocument直接来遍历什么东西特别的慢,所以我们需要的是xpath。xpath对于xml就跟regex对于字符串一样,可以直接查询出我们要的东西。首先看一下如何操作IXMLDOMDocument2接口:

IXMLDOMNodeList* XmlQuery(IXMLDOMNode* pDom, const WString& xpath)
{
    IXMLDOMNodeList* nodes=0;
    BSTR xmlQuery=SysAllocString(xpath.Buffer());
    if(xmlQuery)
    {
        HRESULT hr=pDom->selectNodes(xmlQuery, &nodes);
        if(FAILED(hr))
        {
            nodes=0;
        }
        SysFreeString(xmlQuery);
    }
    return nodes;
}

WString XmlReadString(IXMLDOMNode* node)
{
    WString result;
    BSTR text=0;
    HRESULT hr=node->get_text(&text);
    if(SUCCEEDED(hr))
    {
        const wchar_t* candidateItem=text;
        result=candidateItem;
        SysFreeString(text);
    }
    return result;
}

void XmlReadMultipleStrings(IXMLDOMNodeList* textNodes, List<WString>& candidates, int max)
{
    candidates.Clear();
    while((int)candidates.Count()<max)
    {
        IXMLDOMNode* textNode=0;
        HRESULT hr=textNodes->nextNode(&textNode);
        if(hr==S_OK)
        {
            candidates.Add(XmlReadString(textNode));
            textNode->Release();
        }
        else
        {
            break;
        }
    }
}

IXMLDOMDocument2* XmlLoad(const WString& content)
{
    IXMLDOMDocument2* pDom=0;
    HRESULT hr=CoCreateInstance(__uuidof(DOMDocument60), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDom));
    if(SUCCEEDED(hr))
    {
        pDom->put_async(VARIANT_FALSE);
        pDom->put_validateOnParse(VARIANT_FALSE);
        pDom->put_resolveExternals(VARIANT_FALSE);

        BSTR xmlContent=SysAllocString(content.Buffer());
        if(xmlContent)
        {
            VARIANT_BOOL isSuccessful=0;
            hr=pDom->loadXML(xmlContent, &isSuccessful);
            if(!(SUCCEEDED(hr) && isSuccessful==VARIANT_TRUE))
            {
                pDom->Release();
                pDom=0;
            }
            SysFreeString(xmlContent);
        }
    }
    return pDom;
}

有了这几个函数之后,我们就可以干下面的事情,譬如说从鸟窝首页下载第一页的所有topic的标题:

WString xml=NestleGetXml(L”/topics”, cookie);
IXMLDOMDocument2* pDom=XmlLoad(xml);
List<WString> titles;
IXMLNodeList* nodes=XmlQuery(pDom, L”/hash/topics/topic/title/text()”);
XmlReadMultipleStrings(nodes, titles, 100);

为什么上面的xpath是hash/topics/topic/title/text()呢?因为这个xml的内容大概类似于:
<hash>
    <topics>
        <topic>
            <title>TITLE</title>

剩下的大家就去看代码吧。这个故事告诉我们,只要有一个合适的封装,C++写起这些本来应该让C#来写的东西也不是那么的烦人的,啊哈哈哈哈。

posted on 2012-10-26 23:19 陈梓瀚(vczh) 阅读(3748) 评论(1)  编辑 收藏 引用 所属分类: C++

评论:
# re: 使用C++和Windows API操作基于http协议的xml service 2012-10-27 05:50 | huliang
牛逼~~ 一开始还真看成是C#的 HttpResponse 了  回复  更多评论
  

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理