本帖最後由 michael3636 於 2015-5-1 20:00 編輯 Part 5
老規矩,來點知識普及:
字符編碼: 啥是編碼?為啥瀏覽器從來不亂碼,我用XHR老會碰到亂碼?讓我們解開這個秘密吧
什麼決定了網頁的編碼?2個地方
- 一個服務器返回頭部裡的」Conten-type」,如果裡面有"CharSet"鍵,瀏覽器就根據這個鍵指定的值去設置網頁編碼
- 如果1里面沒有"CharSet",瀏覽器就去網頁源代碼找charset相關的值,大家可以右鍵查看源文件,去搜索這個關鍵字,一般都在網頁開頭的地方,這裡設定了網頁的編碼,瀏覽器根據這裡的設定設定網頁的編碼
以下為本帖隱藏內容
==============================
XHR呢?它只管1,不管2,也就是說,1里指定了,,它就能正確編碼字符串,1里不指定,它鐵定亂碼,以前默認是」utf-8」,就算1里不指定它就默認用這個編碼,現在連默認都省了.直接給你亂碼看
==============================
通過查看源文件,我們能知道,按鍵和新浪都是」GBK」編碼的,為啥用xhr去玩,一個是亂碼一個是正常的呢?
代碼說話:
- //看按鍵
- Set http = CreateObject("WinHttp.WinHttpRequest.5.1")//創建XHR對象
- URL = "http://bbs.anjian.com/forum.php?mod=forumdisplay&fid=17"//按鍵論壇
- http.open "GET", URL, False
- http.send
- If Not isEmpty(http.responsetext) Then
- MessageBox http.getresponseheader("content-type") //看看content-type內容
- Else MessageBox "失敗"
- End If
- //看新浪
- URL = "http://www.sina.com.cn" //看新浪
- http.open "GET", URL, False
- http.send
- If Not isEmpty(http.responsetext) Then
- MessageBox http.getresponseheader("content-type") //看看content-type內容
- Else MessageBox "失敗"
- End If
複製代碼明白了吧…只要服務器表頭裡的」Conten-type」設置了編碼,XHR就能正常工作啦,,,如果不指定,亂碼啦..那有人會說了,我在Part 3 裡的獲取」網頁源文件」哪個函數完全是可以一個參數的搞定的,只要在返回的源文件裡查下」charset」對應的編碼,函數豈不是可以自動正確編碼了麼?沒錯,你說的是沒錯,但是我是不推薦的,要知道源文件是很大的,成千上萬個字符,這樣的字符串操作是很慢的,為了省個參數放棄效率,我個人不削為之,但是去」content-type」檢查下我是很樂意的,(畢竟很短的字符串),有」charset」的就不根據參數2轉碼直接輸出,沒有的根據參數轉碼!!!!!
當然,這僅僅是我個人的偏好,大家不喜歡可以去改嘛!!!
符合我個人口味的高效率"獲得網頁源文件"函數
- Function 獲得網頁源文件(網頁地址,網頁編碼) //多個參數.設置編碼.跟亂碼說88
- Dim xmlHttp, xmlUrl,ObjStream
- If InStr(網頁地址, "http://") = 0 Then
- xmlUrl = "http://" & 網頁地址
- Else
- xmlUrl = 網頁地址
- End if
- Set xmlHttp = CreateObject("WinHttp.WinHttpRequest.5.1") //用這個對象,跟緩存/cookie 干擾說88
- xmlHttp.Open "GET", xmlUrl, True
- xmlHttp.Send
- If xmlhttp.waitforresponse() Then
- If instr(1,xmlhttp.getresponseheader("content-type"), "charset",1) Then //通過判斷"content-type"是否有"charset"字符串來決定是否根據參數2轉碼
- 獲得網頁源文件 = xmlHttp.ResponseText
- Exit Function
- Else
- Set ObjStream = CreateObject("Adodb.Stream")
- ObjStream.Type = 1
- ObjStream.Mode = 3
- ObjStream.Open
- ObjStream.Write xmlHttp.ResponseBody
- ObjStream.Position = 0
- ObjStream.Type = 2
- ObjStream.Charset = 網頁編碼
- 獲得網頁源文件 = ObjStream.ReadText
- End If
- Else
- 獲得網頁源文件=False //如果獲取失敗返回值是false
- End If
- End Function
複製代碼
瞭解了XHR的工作編碼機制,我們現在要說的是將是我們在玩
XHR的時候需要切實掌握的編碼知識:
我們需要處理的編碼分2部分
- 我們從服務器收到的字符的編碼: 也就是源文件的編碼,這個在上面和Part 3 裡講的很詳細了
- 我們發給服務器的字符的編碼: 我們發給服務器的東西無非就是 2個部分,URL和我們發送的內容需要處理編碼問題
當我們的URL裡帶查詢語句的時候(就是網頁地址裡有"?","?"後面的就是查詢參數),而這個查詢字符是中文(或其他非英文語言)的時候,我們不得不面對這些字符的編碼問題,就跟 Part 4 裡的問題:
如果我們要用"GET"方式登錄我們的中文賬號腫麼辦? 這勢必讓我們面臨url裡帶這中文這個問題,直接提交是肯定登錄不上的,讓我們通過學習解決這個問題吧
先大體說下ulr的規則,url的建議規則是,凡是中文這樣的非asc字符,必須編碼,編碼的形式是:類似 %2位數字%2位數字等等
比如"按鍵"這2個字:根據url建議規則,它應該是這樣的:
%E6%8C%89%E9%94%AE (utf-8的編碼),或者
%B0%B4%BC%FC (gbk/gb2312編碼)
很明顯.按鍵論壇是gbk編碼的.後者才是適合我們的編碼,後者加在url裡才會正確,是的的確是這樣
一個好消息是:其實就URL而言,很多大家都並不是很遵守,很多網站都可以直接提交字符,而不需要進過編碼加工,比如,按鍵,百度,淘寶等等等等,我們只要發送符合網頁編碼的字符就行了,而不需要轉成"%"這種形式,就按鍵而言,我們只要把XHR對象的
某個屬性設置成936就行了如下(詳見Part 3):
http.[option](2)=936url的問題就解決啦..現在你可定堂而皇之的用"GET"方法登陸你的中文賬號啦
post是可以帶著內容向URL地址提交數據的,它的內容編碼腫麼辦,很遺憾的告訴大家,除了豐衣足食自己動手,沒有其他辦法
8過麼,能解決就好
還沒寫完啊..咋就發出來了..我點的保存啊.....不是發佈啊......啊啊啊啊啊啊好咯,進入今天的主題:
如何從又長又亂糟糟的源文件字符串裡得到我們需要的信息?
設定個目標:
我們要從按鍵論壇=>綜合版塊第一頁取得所有的帖子標題,作者,發佈日期,並且得到進入對應帖子的關鍵數據
3個方法
這個麼…俺有火槍了,鐵定不會用板磚,打死你我也不會用這個方法,據說有的」大神」會去用,我只能呵呵了
2. 用無所不能的正則
極力推薦.高效又方便,看代碼:
分析:大家看圖1,這是其中一個普通帖子(非置頂帖)在源文件裡的字段,我們用正則把我們需要的提取出來,上代碼!!!
- Set http = CreateObject("WinHttp.WinHttpRequest.5.1")//創建XHR對象
- URL = "http://bbs.anjian.com/forum.php?mod=forumdisplay&fid=17"//按鍵論壇
- http.open "GET", URL, True
- http.send
- If http.waitforresponse() Then
- text= http.responsetext //為了方便大家看代碼,把返回的文本賦值給text變量
- Else MessageBox "失敗"
- End If
- //開始處理返回的源文件字符串,正則
- Set re = New regexp
- re.[global] = true
- re.IgnoreCase = True
- //下面就是提取指定信息的正則表達式
- re.pattern = "<tbody id=""normalthread_(\d*)""[\s\S]+?class=""xst"" >([^<]*)<[\s\S]*?c=""1"">([^<]*)<[\s\S]*?>(\d{4}-\d{1,2}-\d{1,2})"
- Set matches = re.execute(text)
- For Each match In matches
- TracePrint match.submatches(1) & " : " & match.submatches(2) & " : " & match.submatches(3)//調試輸出信息看看
- TracePrint "帖子的關鍵數據:" & match.submatches(0)
- Next
複製代碼呵呵呵..正則真好!!!
3.
用HTML DOM 去玩,喜歡玩IE對象的夥伴們高興了.關於html Dom, 又是個超大話題.不展開,會的就用,不會我也米辦法,代碼如下:
- Set http = CreateObject("WinHttp.WinHttpRequest.5.1")//創建XHR對象
- URL = "http://bbs.anjian.com/forum.php?mod=forumdisplay&fid=17"//按鍵論壇
- http.open "GET", URL, True
- http.send
- If http.waitforresponse() Then
- text= http.responsetext //為了方便大家看代碼,把返回的源文件文本賦值給text變量
- Else MessageBox "失敗"
- End If
- //開始處理返回的源文件字符串.html dom
- Set doc = CreateObject("htmlfile") //dom對象
- doc.designMode="on"
- doc.write text
- Set tbds = doc.getelementsbytagname("tbody")
- For Each tbd In tbds
- If instr(tbd.id,"normalthread") Then
- Set ass = tbd.getelementsbytagname("a")
- For Each a In ass
- If a.classname = "xst" Then
- Set b=a.parentnode.nextSibling
- TracePrint a.innertext & " " & b.innertext
- End If
- Next
- End if
- Next
複製代碼
好啦..在源文件裡提取我們需要的內容的方式介紹完了.這個怎麼說呢.會者不難難者不會,就理性建議而言,2/3兩種方法都可以,1就算了,具體哪種看你熟悉哪種吧,如果啥都不會,那就去學一種推薦學正則,不學的話.學XHR是沒有任何意義的.