日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

如何定制一款12306抢票浏览器——用户界面

發布時間:2023/11/27 生活经验 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何定制一款12306抢票浏览器——用户界面 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ? ? 用戶界面

? ? ? ? 我不打算寫個Windows界面。因為這個軟件的全部就是個瀏覽器。我準備將”瀏覽器“進行到底,所以我選擇使用html作為我們的用戶界面。我也并不打算從頭開始寫一個瀏覽器,我使用了《內嵌IE網頁窗口中消除IE默認腳本設置影響的方法》中基于WTL的瀏覽器代碼。(轉載請指明出于breaksoftware的csdn博客)界面如下

? ? ? ? ?我觀察了下12306的頁面,它預留了5個乘客信息,所以我也就預留了5個乘客信息。因為我不會寫HTML和javascript,我就從12306中copy出相應的頁面元素,并加以修改。在此感謝下12306網頁設計同學,幫我完成了不少我不會的東西。

? ? ? ? 一般來說,我們可能一次性不會購買5個人的票。所以在上面的界面中,你想填多少人信息就填多少人信息,我會在代碼中讀取這些人的信息。當我們填完乘客信息后,我們要輸入車次信息。然后我們要點擊一下確定,我會在代碼中捕獲點擊確定的操作,并將已經填寫的信息讀入內存。在之后的搶票過程中,我們將使用到這些信息。最后,我們就要點擊最下面那個超鏈接,跳轉到12306這個頁面,開始我們真正的搶票工作。

? ? ? ? 我們來看一下源代碼。首先是界面的,我列一個人的信息代碼出來:

<tr class="passenger_class" id="passenger_1"><td style="width: 6%"><div id="passenger_1_index">第1位</div></td><td id="seat"><select><option value="1">硬座</option><option value="2">軟座</option><option value="3">硬臥</option><option value="4">軟臥</option><option value="6">高級軟臥</option><option value="M">一等座</option><option value="O">二等座</option><option value="P">特等座</option><option value="9">商務座</option></select> </td><td style="width: 20%"><label><strong>請確認所選車次有該坐席</strong> </label></td><td id="ticket"><select><option value="1">成人票</option><option value="2">兒童票</option><option value="3">學生票</option><option value="4">殘軍票</option></select></td><td id="name"><input name="passenger_1_name" type="text" id="passenger_1_name" size="12" maxlength="20" class="input_20txt" value=""/></td><td id="cardtype"><select><option value="1">二代身份證</option><option value="2">一代身份證</option><option value="C">港澳通行證</option><option value="G">臺灣通行證</option><option value="B">護照</option></select></td><td id="cardno"><input name="passenger_1_cardno" type="text" id="passenger_1_cardno" size="20" maxlength="35" style="text-transform: uppercase;" class="input_20txt" value=""/></td><td id="mobileno"><input name="passenger_1_mobileno" type="text" id="passenger_1_mobileno" size="11" maxlength="20" class="input_20txt" value=""/></td>
</tr>

? ? ? ? 因為我并不知道用戶選擇的車次有什么類型的座位,所以我將所有的座位都列了出來。

		<select><option value="1">硬座</option><option value="2">軟座</option><option value="3">硬臥</option><option value="4">軟臥</option><option value="6">高級軟臥</option><option value="M">一等座</option><option value="O">二等座</option><option value="P">特等座</option><option value="9">商務座</option></select> 

? ? ? ? 這兒要特別注意下所有option的value字段,這些值不是我亂取的。而是我檢查了12306頁面的很多火車信息后收集到的。我們會在之后記錄用戶所選席別時,記錄這些值,因為這些值將在操作12306頁面時派上用場。

? ? ? ? 其他元素應該沒什么可以解釋的,只是要注意所有Select下的Option的Value值和12306上對應的元素的Value值一致。

? ? ? ? 我們保存單個用戶的結構體是

struct StSinglePassengerInfo{ListCString ListSeat;CString cstrTicket;CString cstrName;CString cstrCardtype;CString cstrCardNo;CString cstrMobileNo;
};

? ? ? ? 注意一下ListSeat這個字段,這個字段保存的一個CString的隊列。它記錄著一系列席別代碼。在我最開始設計這個軟件時,我是希望用戶可以選擇一系列可以接受的席別,同時是按優先級關系排列。這樣可以最大程度上滿足用戶的需求。但是我已無心把這個功能繼續做下去,所以設計界面時,只能讓用戶選擇一個席別。

? ? ? ? 還有一個需要我們關注的是“確定”超鏈接的代碼

<td><a style="width: 60px;" href="http://settingok">確定</a>
</td>

? ? ? ? 我們點擊“確定”按鈕后,頁面理論上要跳轉到“http://settingok”這個頁面。而實際上,我們只是利用“跳轉”這個操作,讓我們的C++代碼中捕獲到用戶已經設置OK了。我們并不希望頁面真的發生跳轉。所以我們對BeforeNavigate2消息映射函數做了處理,讓跳轉到“http://settingok”的請求終止,并讀取用戶設置的乘客信息和車次信息。

void CBrowserHost::BeforeNavigate2(IDispatch *pDisp, VARIANT *url,VARIANT *Flags, VARIANT *TargetFrameName, VARIANT *PostData,VARIANT *Headers, VARIANT_BOOL *Cancel)
{do  {if ( NULL != url ) {CString cstrUrl((LPWSTR)(url->bstrVal));if ( 0 == cstrUrl.CompareNoCase(SETTINGOK) ) {*Cancel = VARIANT_TRUE;CComPtr<IWebBrowser2> spWeb;HRESULT hr = pDisp->QueryInterface(IID_IWebBrowser2, (LPVOID*)&spWeb);CHECKHRPOINTER(hr, spWeb);CComPtr<IDispatch> dispDoc;hr = spWeb->get_Document(&dispDoc);CHECKHRPOINTER(hr, dispDoc);CComPtr<IHTMLDocument2> spDoc;hr = dispDoc->QueryInterface( IID_IHTMLDocument2, (LPVOID*)&spDoc);CHECKHRPOINTER(hr, spDoc);StTrainNoPassengerInfo stTrainPassenger;hr = m_dealSettingPage.GetTrainNoPassengersInSettingPage(spDoc, stTrainPassenger);hr = m_AutoMan.SetTrainNoPassengers(stTrainPassenger);}……}……} while (0);
}

? ? ? ? 上面代碼中m_dealSettingPage是我處理頁面的類CDeal12306WebPage的對象。GetTrainNoPassengersInSettingPage將解析網頁保存乘客和車次信息。m_AutoMan是我們之前說的“人”線程,此時我們將告訴該線程所有信息,讓它準備開始工作。

HRESULT CDeal12306WebPage::GetTrainNoPassengersInSettingPage( CComPtr<IHTMLDocument2> & spDoc,StTrainNoPassengerInfo & stTrainPassenger )
{HRESULT hr = E_FAIL;do {CComPtr<IHTMLElement> spBody;hr = spDoc->get_body(&spBody);CHECKHRPOINTER(hr, spBody);CComPtr<IHTMLElement> spTable;hr = GetElementByID(spBody, L"passengertable", spTable);CHECKHRPOINTER(hr, spTable);CComPtr<IHTMLElement> spTBody;hr = GetElementByIndex( spTable, 0, spTBody);CHECKHRPOINTER(hr, spTBody);for ( int i = 0; i < MAXPASSENGERCOUNT; i++ ) {CString cstrTrID;cstrTrID.Format(PASSENGERID, i + 1);CComPtr<IHTMLElement> spTr;hr = GetElementByID( spTBody, cstrTrID, spTr);CHECKHRPOINTER(hr, spTr);StSinglePassengerInfo stSinglePassenger;hr = GetPassengerInfo(spTr, stSinglePassenger);CHECKHR(hr);if ( FALSE == stSinglePassenger.cstrName.IsEmpty() &&FALSE == stSinglePassenger.cstrTicket.IsEmpty() &&FALSE == stSinglePassenger.cstrCardNo.IsEmpty() &&FALSE == stSinglePassenger.cstrCardtype.IsEmpty() &&FALSE == stSinglePassenger.cstrMobileNo.IsEmpty() &&0 != stSinglePassenger.ListSeat.size()) {stTrainPassenger.vecPassengerInfo.push_back(stSinglePassenger);}}hr = GetTrainNoInSettingPage(spDoc, stTrainPassenger.cstrTrainNo);} while (0);return hr;
}

? ? ? ? 這段代碼大致意思是在“設置”頁面中,找到id為passengertable的元素spTable,然后找到spTable下第一個元素spTBody。spTBody下保存著每個乘客的信息,其中第一個乘客信息保存在id是“passenger_1”的元素下,第二個保存在“passenger_2”元素下……當單個乘客所有信息都不為空時,將其保存在一個stTrainPassenger.vecPassengerInfo中。最后我們要獲取火車車次的信息,將其保存在stTrainPassenger.cstrTrainNo中。
? ? ? ? 上面的函數大部分是經過封裝的。其中幾個經常用的函數是

	HRESULT GetElementCollection(CComPtr & spElem,CComPtr & spElemCollection );enum EQUERYTYPE {EID,ETAGNAME,ECLASSNAME,};// 通過ID獲取指定節點下第一個ID為cstrID的子節點HRESULT GetElementByID(CComPtr<IHTMLElement> & spElem, const CString & cstrID,CComPtr<IHTMLElement> & spResElem);// 通過ClassName獲取指定節點下第一個class為cstrClassName的子節點HRESULT GetElementByClassName(CComPtr<IHTMLElement> & spElem, const CString & cstrClassName,CComPtr<IHTMLElement> & spResElem);// 通過TagName獲取指定節點下第一個tag為cstrTagName的子節點HRESULT GetElementByTagsName(CComPtr<IHTMLElement> & spElem, const CString & cstrTagName,CComPtr<IHTMLElement> & spResElem);// 通過ID獲取指定節點下第lindex子節點HRESULT GetElementByIndex(CComPtr<IHTMLElement> & spElem, LONG lIndex,CComPtr<IHTMLElement> & spResElem);HRESULT GetElement(CComPtr & spElem, EQUERYTYPE eType, const CString & cstrValue,CComPtr & spResElem);& spElem,CComPtr & spElemCollection );enum EQUERYTYPE {EID,ETAGNAME,ECLASSNAME,};// 通過ID獲取指定節點下第一個ID為cstrID的子節點HRESULT GetElementByID(CComPtr<IHTMLElement> & spElem, const CString & cstrID,CComPtr<IHTMLElement> & spResElem);// 通過ClassName獲取指定節點下第一個class為cstrClassName的子節點HRESULT GetElementByClassName(CComPtr<IHTMLElement> & spElem, const CString & cstrClassName,CComPtr<IHTMLElement> & spResElem);// 通過TagName獲取指定節點下第一個tag為cstrTagName的子節點HRESULT GetElementByTagsName(CComPtr<IHTMLElement> & spElem, const CString & cstrTagName,CComPtr<IHTMLElement> & spResElem);// 通過ID獲取指定節點下第lindex子節點HRESULT GetElementByIndex(CComPtr<IHTMLElement> & spElem, LONG lIndex,CComPtr<IHTMLElement> & spResElem);HRESULT GetElement(CComPtr & spElem, EQUERYTYPE eType, const CString & cstrValue,CComPtr & spResElem);
?

? ? ? ? 對應的實現代碼是

HRESULT CDeal12306WebPage::GetElementCollection( CComPtr<IHTMLElement> & spElem, CComPtr<IHTMLElementCollection> & spElemCollection )
{HRESULT hr = S_FALSE;do {CComPtr<IDispatch> spDispatch;hr = spElem->get_children(&spDispatch);CHECKHR(hr);hr = spDispatch->QueryInterface( IID_IHTMLElementCollection, (LPVOID*)&spElemCollection);CHECKHR(hr);} while (0);return hr;
}HRESULT CDeal12306WebPage::GetElementByID( CComPtr<IHTMLElement> & spElem, const CString & cstrID, CComPtr<IHTMLElement> & spResElem )
{return GetElement( spElem, EID, cstrID, spResElem );
}HRESULT CDeal12306WebPage::GetElementByClassName( CComPtr<IHTMLElement> & spElem, const CString & cstrClassName, CComPtr<IHTMLElement> & spResElem )
{return GetElement( spElem, ECLASSNAME, cstrClassName, spResElem );
}HRESULT CDeal12306WebPage::GetElementByTagsName( CComPtr<IHTMLElement> & spElem, const CString & cstrTagName, CComPtr<IHTMLElement> & spResElem )
{return GetElement( spElem, ETAGNAME, cstrTagName, spResElem );
}HRESULT CDeal12306WebPage::GetElementByIndex( CComPtr<IHTMLElement> & spElem, LONG lIndex, CComPtr<IHTMLElement> & spResElem )
{HRESULT hr = E_FAIL;do {CComPtr<IHTMLElementCollection> spElemCollecion;hr = GetElementCollection( spElem, spElemCollecion);CHECKHR(hr);LONG lCollecionCount = 0;hr = spElemCollecion->get_length(&lCollecionCount);CHECKHR(hr);if ( lCollecionCount < lIndex + 1) {break;}CComVariant VarIndex = lIndex;CComPtr<IDispatch> spDisp;hr = spElemCollecion->item(VarIndex, VarIndex, &spDisp);CHECKHRPOINTER(hr,spDisp);hr = spDisp->QueryInterface(IID_IHTMLElement, (LPVOID*)&spResElem);} while (0);return hr;
}HRESULT CDeal12306WebPage::GetElement( CComPtr<IHTMLElement> & spElem, EQUERYTYPE eType, const CString & cstrValue, CComPtr<IHTMLElement> & spResElem )
{HRESULT hr = E_FAIL;do {CComPtr<IHTMLElementCollection> spElemCollection;hr = GetElementCollection( spElem, spElemCollection);CHECKHRPOINTER(hr,spElemCollection);LONG lCollecionCount = 0;hr = spElemCollection->get_length(&lCollecionCount);CHECKHR(hr);for ( long i = 0; i < lCollecionCount; i++ ) {CComVariant VarIndex = i;CComPtr<IDispatch> spDispatchElem;hr = spElemCollection->item( VarIndex, VarIndex, &spDispatchElem );CHECKHRPOINTER(hr,spDispatchElem);CComPtr<IHTMLElement> spElem;hr = spDispatchElem->QueryInterface(IID_IHTMLElement, (LPVOID*)& spElem );CHECKHRPOINTER(hr, spElem);CComBSTR bstrValue;switch (eType) {case EID: {hr = spElem->get_id(&bstrValue);}break;case ETAGNAME: {hr = spElem->get_tagName(&bstrValue);}break;case ECLASSNAME: {hr = spElem->get_className(&bstrValue);}break;default:break;}CString cstrV((LPWSTR)bstrValue);if ( 0 == cstrV.CompareNoCase( cstrValue )) {spResElem = spElem;break;}}} while (0);return hr;
}

? ? ? ? 在獲取乘客和車次信息時用到的其他封裝函數的實現是

HRESULT CDeal12306WebPage::GetPassengerInfo( CComPtr<IHTMLElement> & spElem, StSinglePassengerInfo & stSinglePassenger )
{HRESULT hr = E_FAIL;do {CString cstrSeat;hr = GetOptionValueHelper(spElem, L"seat", cstrSeat);CHECKHR(hr);stSinglePassenger.ListSeat.push_back(cstrSeat);hr = GetOptionValueHelper(spElem, L"ticket", stSinglePassenger.cstrTicket );CHECKHR(hr);hr = GetOptionValueHelper(spElem, L"cardtype", stSinglePassenger.cstrCardtype);CHECKHR(hr);hr = GetInputValueHelper(spElem, L"name", stSinglePassenger.cstrName);CHECKHR(hr);hr = GetInputValueHelper(spElem, L"cardno", stSinglePassenger.cstrCardNo);CHECKHR(hr);hr = GetInputValueHelper(spElem, L"mobileno", stSinglePassenger.cstrMobileNo);} while (0);return hr;
}HRESULT CDeal12306WebPage::GetOptionValueHelper( CComPtr<IHTMLElement> & spElem, const CString& cstrID, CString& cstrValue )
{HRESULT hr = E_FAIL;do {CComPtr<IHTMLElement> spTd;hr = GetElementByID(spElem, cstrID, spTd);CHECKHRPOINTER(hr, spTd);CComPtr<IHTMLElement> spSel;hr = GetElementByIndex(spTd, 0, spSel);CHECKHRPOINTER(hr, spSel);CComPtr<IHTMLSelectElement> spSelect;hr = spSel->QueryInterface(IID_IHTMLSelectElement, (LPVOID*)&spSelect);CHECKHRPOINTER(hr, spSelect);CComBSTR bstrValue;hr = spSelect->get_value(&bstrValue);CHECKHR(hr);cstrValue = bstrValue;} while (0);return hr;
}HRESULT CDeal12306WebPage::GetInputValueHelper( CComPtr<IHTMLElement> & spElem,const CString& cstrID, CString & cstrValue )
{HRESULT hr = E_FAIL;do {CComPtr<IHTMLElement> spTd;hr = GetElementByID(spElem, cstrID, spTd);CHECKHRPOINTER(hr, spTd);CComPtr<IHTMLElement> spInput;hr = GetElementByIndex(spTd, 0, spInput);CHECKHRPOINTER(hr, spInput);CComPtr<IHTMLInputElement> spInputElem;hr = spInput->QueryInterface(IID_IHTMLInputElement, (LPVOID*)&spInputElem);CHECKHRPOINTER(hr, spInputElem);CComBSTR bstrValue;hr = spInputElem->get_value(&bstrValue);CHECKHR(hr);cstrValue = bstrValue;} while (0);return hr;
}HRESULT CDeal12306WebPage::GetTrainNoInSettingPage( CComPtr<IHTMLDocument2> & spDoc, CString & cstrValue )
{HRESULT hr = E_FAIL;do {CComPtr<IHTMLElement> spBody;hr = spDoc->get_body(&spBody);CHECKHRPOINTER(hr, spBody);CComPtr<IHTMLElement> spTable;hr = GetElementByID(spBody, L"trainnotable", spTable);CHECKHRPOINTER(hr, spTable);CComPtr<IHTMLElement> spTBody;hr = GetElementByIndex( spTable, 0, spTBody);CHECKHRPOINTER(hr, spTBody);CComPtr<IHTMLElement> spTr;hr = GetElementByIndex(spTBody, 0, spTr);CHECKHRPOINTER(hr, spTr);CComPtr<IHTMLElement> spTd;hr = GetElementByID(spTr, L"trainno", spTd);CHECKHRPOINTER(hr, spTd);CComPtr<IHTMLElement> spInput;hr = GetElementByIndex(spTd, 0, spInput);CHECKHRPOINTER(hr, spInput);CComPtr<IHTMLInputElement> spInputElem;hr = spInput->QueryInterface(IID_IHTMLInputElement, (LPVOID*)&spInputElem);CHECKHRPOINTER(hr, spInputElem);CComBSTR bstrValue;hr = spInputElem->get_value(&bstrValue);CHECKHR(hr);cstrValue = bstrValue;} while (0);return hr;
}

?

總結

以上是生活随笔為你收集整理的如何定制一款12306抢票浏览器——用户界面的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。