大家經(jīng)常需要將網(wǎng)站上面的數(shù)據(jù)下載或?qū)氲紼xcel中進(jìn)行匯總分析,例如股票數(shù)據(jù)等,這樣可以充分利用Excel強(qiáng)大的數(shù)據(jù)分析功能。在Excel中下載網(wǎng)頁數(shù)據(jù)的方法有很多種,包括WebBrowser控件、控制IE、Web查詢、API函數(shù),這里主要介紹XML庫的XMLHTTPRequest對(duì)象。
使用XMLHTTPRequest對(duì)象的好處是不需要打開瀏覽器而在后臺(tái)下載數(shù)據(jù),這樣可以保持干凈的界面,另外能夠很方便的使用POST方法遞交查詢表單的數(shù)據(jù),同時(shí)XMLHTTPRequest對(duì)象可以處理各種類型的數(shù)據(jù),例如javascript數(shù)據(jù)、json數(shù)據(jù)、xml數(shù)據(jù)以及各種圖像數(shù)據(jù)等,特別是對(duì)于一些Web服務(wù),使用XMLHTTPRequest是很好的選擇。但XMLHTTPRequest對(duì)象一定程度上依賴于網(wǎng)頁的源代碼,如果源代碼發(fā)生變化,處理數(shù)據(jù)的方法也需要相應(yīng)地做出改變。
在前面的文章中已經(jīng)介紹過XMLHTTPRequest對(duì)象的方法和屬性,這里主要介紹使用XMLHTTPRequest對(duì)象的一般流程,以新浪的天氣預(yù)報(bào)查詢做為例子。
1. 首先分析網(wǎng)頁源代碼,獲得所需要遞交的數(shù)據(jù),這個(gè)步驟很關(guān)鍵,需要了解部分HTML和腳本知識(shí)
查看網(wǎng)頁源代碼時(shí),主要是分析要遞交的表單(Form元素)包含哪些Input元素、處理表單的URL地址、表單的遞交方法。
例如,打開新浪天氣的網(wǎng)頁http://php.weather.sina.com.cn/widget/search_middle.php,可以看到下面這個(gè)輸入框,這就是一個(gè)查詢表單。
在源代碼中搜索“搜索城市天氣”,可以找到這個(gè)form元素的代碼:
<form name="city" method="get" action="http://php.weather.sina.com.cn/search.php" style=""> <span>搜索城市天氣:</span><input type="text" name="city" value="輸入國別、地名、拼音、電 話區(qū)號(hào)均可" onclick="javascript:if(this.value=='輸入國別、地名、拼音、電話區(qū)號(hào)均可')this.value='';" class="city" style="width:220px;" /> <input type="hidden" name="f" value="1" /><input type="hidden" name="dpc" value="1" /><input type="submit" class="cityBtn" value="搜索" style="width:50px;" /> </form>
根據(jù)這個(gè)代碼,從form元素的action屬性可以得到處理表單的網(wǎng)址是“http://php.weather.sina.com.cn/search.php”,從method屬性可以得到數(shù)據(jù)遞交的方法是“get”,根據(jù)其中input元素的name和value屬性可以知道需要遞交的數(shù)據(jù)一共有三個(gè),其中city可以使用地名、拼音和電話區(qū)號(hào),服務(wù)器端可以自動(dòng)處理。
city=東莞 f=1 dpc=1
2. 創(chuàng)建HTTPRequest對(duì)象
使用前綁定的話需要引用XML庫,如圖:

Dim httpRequest As MSXML2.XMLHTTP30 Set httpRequest = New MSXML2.XMLHTTP30
或者使用后綁定:
Dim httpRequest As Object Set httpRequest = CreateObject("MSXML2.XMLHTTP")
3. 使用XMLHTTPRequest對(duì)象建立與指定的網(wǎng)頁URL的連接
根據(jù)前面獲得的Input元素和遞交方法,Open方法使用的參數(shù)有些不同。
首先將需要遞交的數(shù)據(jù)用符號(hào)&連接起來,不限制順序,例如“city=東莞&f=1&dpc=1”和“dpc=1&city=東莞&f=1”均可。
如果使用GET方法,將這個(gè)數(shù)據(jù)和表單處理網(wǎng)址用符號(hào)?連接起來。例如:
httpRequest.Open "GET", "http://php.weather.sina.com.cn/search.php?city=東莞&f=1&dpc=1", False
如果使用POST方法,則在send方法中發(fā)送遞交數(shù)據(jù)。
httpRequest.Open "GET", "http://php.weather.sina.com.cn/search.php", False httpRequest.Send "city=東莞&f=1&dpc=1"
4. 設(shè)置HTTP的頭部信息
一般來說只需要設(shè)置Content-Type的頭部信息就可以了。對(duì)于一般的網(wǎng)頁內(nèi)容,設(shè)置Content-Type為“text/html”,也可以省略。例如:
httpRequest.setRequestHeader "Content-Type", "text/html"
某些情況下,需要設(shè)置為“application/x-www-form-urlencoded”,例如:
httpRequest.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
在實(shí)時(shí)更新數(shù)據(jù)的時(shí)候,有時(shí)每次查詢會(huì)返回第一次查詢后保存在緩存中的數(shù)據(jù),可以設(shè)置HTTP的If-Modified-Since頭部信息,這樣就保證每次下載的都是最新的數(shù)據(jù)。例如:
httpRequest.setRequestHeader "If-Modified-Since", Format(Now, "[$-F800]dddd, mmmm dd, yyyy") & " GMT"
5. 發(fā)送信息
如果是GET方法,發(fā)送空字符串,例如
httpRequest.Send ""
或者
httpRequest.Send
如果使用POST方法,則發(fā)生遞交的數(shù)據(jù),例如:
httpRequest.Send "city=東莞&f=1&dpc=1"
6. 處理返回的內(nèi)容
根據(jù)XMLHTTPRequest對(duì)象的Status屬性判斷是否訪問成功,如果成功則處理HTTPRequest對(duì)象的返回內(nèi)容。
If httpRequest.Status = 200 Then txtContent = httpRequest.responseText ' ... End If
HTTPRequest對(duì)象返回的信息由三個(gè)屬性表示:responseText、responseXML和responseBody。
這里需要注意中文網(wǎng)頁的內(nèi)容,如果返回的網(wǎng)頁源代碼的編碼不是UTF-8的話,由responseText屬性表示返回的內(nèi)容中,中文部分將會(huì)是亂碼,這時(shí)需要處理responseBody屬性來獲得正確的內(nèi)容。
網(wǎng)上有些編碼轉(zhuǎn)換的函數(shù)(例如下面這個(gè)bytes2BSTR函數(shù))在英文操作系統(tǒng)上不能使用。
Function bytes2BSTR(arrBytes) '編碼轉(zhuǎn)換 Dim strReturn As String Dim ThisCharCode As String Dim NextCharCode As String Dim i As Long strReturn = "" arrBytes = CStr(arrBytes) For i = 1 To LenB(arrBytes) ThisCharCode = AscB(MidB(arrBytes, i, 1)) If ThisCharCode < &H80 Then strReturn = strReturn & Chr(ThisCharCode) Else NextCharCode = AscB(MidB(arrBytes, i + 1, 1)) strReturn = strReturn & Chr(CLng(ThisCharCode) * &H100 + CInt(NextCharCode)) i = i + 1 End If Next i bytes2BSTR = strReturn End Function
在英文版操作系統(tǒng)中,如果Office是中文的話,可以直接使用下面的StrConv方法來轉(zhuǎn)換。
StrConv(httpRequest.responseBody, vbUnicode)
上面這個(gè)StrConv方法在英文版Office中不能正確使用。比較安全的方法是使用API函數(shù)MultiByteToWideChar,這樣可以正確轉(zhuǎn)換編碼。
Public Declare Function MultiByteToWideChar Lib "kernel32" (ByVal CodePage As Long, ByVal dwFlags As Long, ByRef lpMultiByteStr As Any, ByVal cchMultiByte As Long, ByVal lpWideCharStr As Long, ByVal cchWideChar As Long) As Long Sub GetWeather(strCity As String) Dim httpRequest As MSXML2.XMLHTTP30 Dim txtContent As String Dim ReturnByte() As Byte Dim lngBufferSize As Long Dim strBuffer As String Dim lngResult As Long If Trim(strCity) = "" Then Exit Sub strQuery = "http://php.weather.sina.com.cn/search.php?" & "city=" & strCity & "&f=1&dpc=1" Set httpRequest = New MSXML2.XMLHTTP30 httpRequest.Open "GET", strQuery, False httpRequest.setRequestHeader "Content-Type", "text/html" httpRequest.send "" If httpRequest.Status = 200 Then ReturnByte = httpRequest.responseBody lngBufferSize = (UBound(ReturnByte) + 1) * 2 strBuffer = String$(lngBufferSize, vbNullChar) lngResult = MultiByteToWideChar(936, 0, ReturnByte(0), lngBufferSize / 2, StrPtr(strBuffer), lngBufferSize) txtContent = Left(strBuffer, lngResult)
另外,如果返回的內(nèi)容是有效的格式,例如RSS Feed或者一些Web服務(wù)等,還可以使用XML庫的DOMDocument對(duì)象來解析HTTPRequest對(duì)象的responseXML屬性內(nèi)容。
Set objXMLHTTP = New MSXML2.XMLHTTP30 objXMLHTTP.Open "GET", strFeedURL, False objXMLHTTP.setRequestHeader "Content-type", "text/html" objXMLHTTP.send If objXMLHTTP.Status = 200 Then Set objXML = New MSXML2.DOMDocument30 objXML.async = False bRet = objXML.Load(objXMLHTTP.responseXML)
7. 如果有網(wǎng)頁內(nèi)容需要翻頁的話,可以根據(jù)前面獲取的內(nèi)容判斷總頁數(shù),然后重復(fù)使用Open和Send方法來獲取所有的數(shù)據(jù)
8. 注銷httpRequest對(duì)象。