在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) 阅读(3887)
评论(1) 编辑 收藏 引用 所属分类:
C++