VBA無法像 JavaScript等程式有現成的編譯函數
所以處理的方式會有點瑣碎,資料必須進行多次的切割
我參考了之前東吳VBA課程吳老師的教學範例
修改成使用XMLHTTP 物件來抓取網頁資料,而不是先將資料存在儲存格中
這是因為一個儲存格中僅能顯示32,767 個字元,如果資料量太多就無法先存在儲存格
只能將資料存在變數之中,再透過字串分割處理來留下需要的資料
使用XMLHTTP 物件必須額外引入Microsoft HTML Object Library
引用物件的方式分為2種
Early Binding 和 Late Binding
Early Binding 就是先在工具->設定引用項目->勾選
之後用 New 物件名稱來建立物件
如果要控制 IE 或者 Windows系統和檔案,也同樣需要引入對應的物件
Late Binding 則是透過CreateObject(物件名稱)
用來練習的檔案都來自政府資料開放平臺
但是這個平臺只是匯集政府各單位的資料
所以不同的單位可能會有不一樣的Json內容
有些是很單純的資料,
有些還會有很多說明資訊,而資料是其中一個屬性內容,例如以下的資料
所以必須針對不同資料型態適當修改程式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
'設定網址 Const URl As String = "https://data.epa.gov.tw/api/v1/aqx_p_432?limit=1000&api_key=9be7b239-557b-4c10-9775-78cadfc555e9&format=json" '分割單筆json資料 {"key1":"value1",....} Sub JSON_Split_Range(S, k) '處理資料 'Debug.Print "S1-" & S S = Replace(S, """", "") 'Debug.Print "S2-" & S S = Replace(S, " ", "") 'Debug.Print "S3-" & S '分割單筆json資料為 key1:value1...... arr = Split(Mid(S, 2, Len(S) - 2), ",") '第一筆跳過{ 開始取字串 第二筆之後跳過 , 得到 key:value格式的字串陣列 'Debug.Print "arr(0)-" & arr(0) c = 1 For i = 0 To UBound(arr) 'Debug.Print "arr(i)" & arr(i) '分割 key1:value1 arr2 = Split(Trim(arr(i)), ":") 'Debug.Print "arr2(0)" & arr2(0) 'Debug.Print "arr2(1)" & arr2(1) If k = 1 Then 'Debug.Print " arr2(0)-"& arr2(0) 'Debug.Print " arr2(1)-"& arr2(1) Cells(k, c) = arr2(0) Cells(k + 1, c) = arr2(1) Else: Cells(k + 1, c) = arr2(1) End If c = c + 1 Next End Sub '透過XMLHTTP 抓取網頁資料 Sub xmlHttp() Application.ScreenUpdating = False '刪除舊資料 Sheets(1).Select Cells.Select Selection.ClearContents Range("A1").Select '設定 XMLHTTP 物件 Dim xmlHttp As Object Set xmlHttp = CreateObject("MSXML2.ServerXMLHTTP.6.0") xmlHttp.Open "GET", URl, False xmlHttp.setRequestHeader "Content-Type", "application/json ; charset=utf-8" xmlHttp.setRequestHeader "Cache-Control", "no-cache" xmlHttp.setRequestHeader "Pragma", "no-cache" xmlHttp.setRequestHeader "User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36" xmlHttp.send '儲存格內容的長度 (文字) '32,767 個字元。在一個儲存格中僅能顯示1,024 個字元;在資料編輯列顯示全部 32,767 個字元。 'XMLHttp Response 'T = xmlHttp.getResponseHeader("content-length") '資料字元數 'P = Len(xmlHttp.ResponseText) '資料內容長度 S = xmlHttp.ResponseText '回傳資料內容 '連線沒問題才處理 If xmlHttp.readyState = 4 Then If xmlHttp.Status = 200 Then '處理抓回來的資料 要依據實際資料進行調整 startVal = InStr(1, S, """" & "records" & """", vbTextCompare) ' "records" startVal = InStr(startVal, S, "[", vbTextCompare) '[ endVal = InStr(startVal, S, "]", vbTextCompare) '] strDiv = Mid(S, startVal, (endVal - startVal) + 1) '從"records" 後取出[{...}] 'Debug.Print "strDiv-" & strDiv 'Debug.Print "Mid(strDiv, 2, Len(strDiv) - 2" & Mid(strDiv, 2, Len(strDiv) - 2) '從[...]取出 {..).{..} - arr = Split(Mid(strDiv, 2, Len(strDiv) - 2), "}") '>split } 最後一個分割 會沒有資料 k = 1 'Debug.Print "UBound(arr)-" &UBound(arr) For i = 0 To UBound(arr) '回傳陣列的index數 'Debug.Print "arr(i)-" & arr(i) If arr(i) <> "" Then '最後一筆分割沒資料 Call JSON_Split_Range(arr(i), k) '再分割 End If k = k + 1 Next End If End If MsgBox ("輸出完成") Application.ScreenUpdating = True End Sub |
完成的樣子
後來在網路上發現可以從excel直接讀取Json檔
Excel 2016從資料→新查詢→其他來源→從Web
網路的教學在從檔案裡就有Json的選項,應該是 2016之後的版本
→貼入Json來源,就可以將資料讀進 Excel Power Query進行處理
因為抓取的Json檔,將資料放在名稱為records屬性裡
所以點擊 records的List
會出現所有records的資料
在清單案右鍵→到表格
或者左上的按鈕也一樣
會出現資料欄位,因為是要抓所有資料,就直接按確定
如果要選擇部分欄位的話,可以按載入更多顯示所有欄位
這邊用預設的”無”就可以了
選其他的分隔符號都無法成功建立表格
成功建立表格
按關閉並載入就會回到Excel
載入的資料會套用表格,並開啟篩選的功能
後記
在過程發生了2個情況
第1個情況是前面有提到的有的Json檔可以直接在網頁開啟,有的卻會直接下載
後者無法在VBA XMLHTTP抓取資料,經過Google大神的開示
這是網頁 HTTP response header之中 Content-Disposition的關係
如果Content-Disposition屬性值為:attachment,就會下載成附件
屬性值如果是inline(默认值 )就會以網頁形式顯示
例如使用Chrome外掛Header Editor修改之後,就能夠直接顯示在瀏覽器頁面
(用xmlHttp.getResponseHeader(“Content-Disposition”)得到的值仍然是attachment)
所以在XMLHTTP增加了xmlHttp.setRequestHeader “Content-Disposition”, “inline”
這樣就能夠抓取資料
備註:後來更新Excel之後,Power Query的”從Web”也可以在”進階”設定Header的參數
備註2:這個方式跟POWER BI一樣,使用了 Power Query M語言建立查詢
第2個情況是在其他電腦利用Excel Power Query建立連線時
會出現”要求已經中止: 無法建立SSL/TLS 的安全通道”
Google大神表示可能是.Net的問題
後來我後來發現兩臺電腦Excel執行”從Web”設定連結的介面不太一樣,有問題的沒有”基礎”、”進階”的選項
所以猜想可能是 Excel Power Query的問題
執行Windows跟Offiec更新(在進階選項要開啟”收到其他Microsoft產品的更新”)
確實.Net 跟 Excel2016 都有更新檔
更新之後就能正常連線了