检查是否进入订票页面
判断是否进入订票页面,我是确定了两个标准:
1 网址是否为http://www.12306.cn/mormhweb/kyfw/
2 该页面否有查询按钮
[cpp]
BOOL CDeal12306WebPage::IsQueryPage( CComPtr<IHTMLDocument2> & spDoc, CComBSTR & bstrUrl )
{
HRESULT hr = E_FAIL;
do {
CString cstrUrl = CString((LPWSTR)bstrUrl);
if ( 0 == cstrUrl.CompareNoCase(LOGIN12306URL) ) {
CComPtr<IHTMLElement> spQueryButton;
hr = GetQueryButtonInQueryPage( spDoc, spQueryButton);
CHECKHRPOINTER(hr, spQueryButton);
}
} while (0);
return FAILED(hr) ? FALSE : TRUE;
}
URL很好检测,那么我们如何判断是否存在查询按钮呢?我们先看一下订票页面的页面特征。
解决跨域问题
可以见得订票页面内部嵌入了两个Iframe,而我们关心的那块页面恰恰就是最里面一层IFrame。那我们直接通过最外层的Doc获取到最里面的Doc,然后在最里面的Doc执行有关的查询操作即可。然而熟悉javascript的同学可能马上就会想到“跨域”问题。其实在浏览器层面,跨域问题是很好解决的。
[cpp]
HRESULT CDeal12306WebPage::GetIFrameDoc( CComPtr<IHTMLDocument2>& spDoc,
const CString& cstrIFrameName, CComPtr<IHTMLDocument2>& spInnerDoc )
{
HRESULT hr = E_FAIL;
do {
CComQIPtr<IHTMLFramesCollection2> spFrameCollection;
hr = spDoc->get_frames(&spFrameCollection);
CHECKHRPOINTER(hr, spFrameCollection);
CComVariant IframeNameReq = CComBSTR(cstrIFrameName.GetString());
CComVariant FramePage;
hr = spFrameCollection->item(&IframeNameReq, &FramePage);
CHECKHRPOINTER(hr,FramePage.pdispVal);
CComPtr<IHTMLWindow2> spIFramePage;
hr = FramePage.pdispVal->QueryInte易做图ce(IID_IHTMLWindow2, (LPVOID*)&spIFramePage);
CHECKHRPOINTER(hr, spIFramePage);
hr = spIFramePage->get_document(&spInnerDoc);
if ( E_ACCESSDENIED == hr ) {
CComQIPtr<IServiceProvider> spServiceProvider = spIFramePage;
CHECKPOINT(spServiceProvider);
CComQIPtr<IWebBrowser2> spInnerWebBrowser;
hr = spServiceProvider->QueryService(IID_IWebBrowserApp, IID_IWebBrowser2, (LPVOID*)&spInnerWebBrowser);
CHECKHRPOINTER(hr, spInnerWebBrowser);
CComPtr<IDispatch> spDisp;
hr = spInnerWebBrowser->get_Document(&spDisp);
CHECKHRPOINTER(hr, spDisp);
hr = spDisp->QueryInte易做图ce(IID_IHTMLDocument2, (LPVOID*)&spInnerDoc);
CHECKHRPOINTER(hr, spInnerDoc);
}
} while (0);
return hr;
}
上面这个函数试图在spDoc页面中获取其内嵌的名字是cstrIFrameName的IFrame的Doc。于是我们要获取其中最里面一层Iframe的Doc可以如下调用
[cpp]
HRESULT CDeal12306WebPage::GetIFrameNamedIFramePageDoc( CComPtr<IHTMLDocument2> & spDoc,
CComPtr<IHTMLDocument2> & spInnerDoc )
{
HRESULT hr = E_FAIL;
do {
hr = GetIFrameDoc(spDoc, L"iframepage", spInnerDoc);
CHECKHRPOINTER(hr, spInnerDoc);
} while (0);
return hr;
}
HRESULT CDeal12306WebPage::GetIFrameNamedMainDoc( CComPtr<IHTMLDocument2> & spIFramPageDoc,
CComPtr<IHTMLDocument2> & spMainDoc )
{
HRESULT hr = E_FAIL;
do {
hr = GetIFrameDoc(spIFramPageDoc, L"main", spMainDoc);
CHECKHRPOINTER(hr, spMainDoc);
} while (0);
return hr;
}
HRESULT CDeal12306WebPage::GetMainDoc( CComPtr<IHTMLDocument2> & spDoc,
CComPtr<IHTMLDocument2> & spMainDoc )
{
HRESULT hr = E_FAIL;
do {
CComPtr<IHTMLDocument2> spIFramePageDoc;
hr = GetIFrameNamedIFramePageDoc(spDoc, spIFramePageDoc);
CHECKHRPOINTER(hr, spIFramePageDoc);
hr = GetIFrameNamedMainDoc(spIFramePageDoc, spMainDoc);
CHECKHRPOINTER(hr, spMainDoc);
} while (0);
return hr;
}
当我们获得最里层的Doc后,我们将根据页面结构获取Class为cx_from的Table元素。
获取这个Table的原因是,之后我们会以该Table为节点,执行“查询按钮”查找的操作。
[cpp]
HRESULT CDeal12306WebPage::GetQueryButtonInQueryPage( CComPtr<IHTMLDocument2> & spDoc, CComPtr<IHTMLElement> & spQueryButtonElem )
{
HRESULT hr = E_FAIL;
do {
CComPtr<IHTMLDocument2> spMainDoc;
hr = GetMainDoc( spDoc, spMainDoc);