判断是否进入预定页面
我们先看一下预定页面的结构
可以见得,这个页面也是嵌入了两个IFrame。关于IFrame的跨域问题,我已经在前一篇文章中讲述了解决办法。
我判断是否是预定页面是通过两个依据:
1 URL是否是
2 是否可以在最里层IFrame中找到class是“table_qr”的元素该元素对应于
具体的查找过程我这儿就不再赘述,我们通过代码来解读
[cpp]
BOOL CDeal12306WebPage::IsBookingPage( CComPtr<IHTMLDocument2> & spDoc, CComBSTR & bstrUrl )
{
HRESULT hr = E_FAIL;
do {
CString cstrUrl = CString((LPWSTR)bstrUrl);
if ( 0 == cstrUrl.CompareNoCase(LOGIN12306URL) ) {
CComPtr<IHTMLElement> spTableQrTbody;
hr = GetTableQrTbody( spDoc, spTableQrTbody);
CHECKHRPOINTER(hr, spTableQrTbody);
}
} while (0);
return FAILED(hr) ? FALSE : TRUE;
}
[cpp]
HRESULT CDeal12306WebPage::GetTableQrTbody( CComPtr<IHTMLDocument2> & spDoc,
CComPtr<IHTMLElement> & spElem )
{
HRESULT hr = E_FAIL;
do {
CComPtr<IHTMLDocument2> spMainDoc;
hr = GetMainDoc( spDoc, spMainDoc);
CHECKHRPOINTER(hr, spMainDoc);
CComPtr<IHTMLElement> spEnter_wElem;
hr = GetEnter_wElement(spMainDoc, spEnter_wElem );
CHECKHRPOINTER(hr, spEnter_wElem);
CComPtr<IHTMLElement> spForm;
hr = GetElementByID( spEnter_wElem, L"confirmPassenger", spForm);
CHECKHRPOINTER(hr, spForm);
CComPtr<IHTMLElement> spTable;
hr = GetElementByClassName( spForm, L"table_qr", spTable);
CHECKHRPOINTER(hr, spTable);
hr = GetElementByIndex( spTable, 0, spElem);
CHECKHRPOINTER(hr, spElem);
} while (0);
return hr;
}
插入用户信息,并设置相应的选项
我们看下用户填写信息的位置的HTML代码结构
我们可以看到5个passenger可填写区域。目前只有第一个显示出来,而其他四个还没有显示。在上图的最下面是个超链接,其对应于“添加1位乘车人”按钮。可以想象,该按钮的一个操作就是将不能显示的tr显示出来。我们“人”线程填写用户信息的过程和人的行为是一致的:填写一个人信息后 ,点击“添加1位乘车人”,再填写一个……我们用代码说明这个过程。
[cpp]
HRESULT CDeal12306WebPage::AddPassengerInfo( CComPtr<IHTMLElement>& spTableQrTbody,
const VecStSinglePassengerInfo& vecStSingleinfo )
{
HRESULT hr = E_FAIL;
do {
// 下标没有从0开始!
int i = 1;
for ( VecStSinglePassengerInfoCIter it = vecStSingleinfo.begin();
it != vecStSingleinfo.end();i++ ) {
CString cstrPassengerId;
cstrPassengerId.Format(PASSENGERID, i);
hr = BookSinglePassenger( spTableQrTbody, cstrPassengerId, it);
CHECKHR(hr);
it++;
if ( it != vecStSingleinfo.end() ) {
AddPassenger(spTableQrTbody);
}
}
} while (0);
return hr;
}
上面代码我们将枚举用户设置的乘客信息。第12行,我们将在table中填写一个乘客信息。第16行,我们将判断最新加入的用户是否是最后一个,如果不是最后一个,则点击“添加1位乘车人”。
[cpp]
HRESULT CDeal12306WebPage::AddPassenger( CComPtr<IHTMLElement> & spTableQrTbody )
{
HRESULT hr = E_FAIL;
do {
CComPtr<IHTMLElement> spTr;
hr = GetElementByIndex(spTableQrTbody, 6, spTr);
CHECKHRPOINTER(hr, spTr);
CComPtr<IHTMLElement> spTd;
hr = GetElementByIndex(spTr, 1, spTd);
CHECKHRPOINTER(hr, spTd);
CComPtr<IHTMLElement> spA;
hr = GetElementByIndex(spTd, 0, spA);
CHECKHRPOINTER(hr, spA);
hr = spA->click();
} while (0);
return hr;
}
填写每个乘客信息的代码是
[cpp]
HRESULT CDeal12306WebPage::BookSinglePassenger( CComPtr<IHTMLElement> & spElem,
const CString& cstrPassengerID, VecStSinglePassengerInfoCIter iter )
{
HRESULT hr = E_FAIL;
do {
CComPtr<IHTMLElement> spTr;
hr = GetElementByID( spElem, cstrPassengerID, spTr );
CHECKHRPOINTER(hr, spTr);