(不定期更新)使用VBA解決 excel web 查詢無法匯入、匯入太慢的股市資料

tmwcykixe wrote:
https://www.cmoney.tw/finance/f00026.aspx?s=6706,這網頁內的資料應參考那個範例抓取或需使用其他方法呢?(恕刪)


xmlhttp 同274樓的寫法
資料是json格式,由其它2個網址回傳、會檢查金鑰

20200421網頁改版,金鑰需轉編碼,可參考269樓的轉碼副程式




網頁所有的選項、連結,都需要有對應的金鑰(每次連線隨機產生)




'範例只示範下載"基本資料"這一頁,2部份資料各取2筆



Sub GET_cmoney_json()

Dim Xmlhttp As Object, Url As String, Url_a As String, Url_b As String, Url_c As String, cmkey As String, stock As String
Dim Jsondata As Object, Json, temp

Set Jsondata = CreateObject("HtmlFile")
Jsondata.write ”<script>document.JsonParse=function (s) {return eval(’(’ + s + ’)’);}</script>”
'jsondata.write 這行是全形字,請自行改成半形,或直接用檔案中的程式碼

Sheets("工作表1").Cells.Clear

stock = InputBox("股票代號", , "6706")
If stock = "" Then Exit Sub

Url = "https://www.cmoney.tw/finance/f00026.aspx?s=" & stock

Set Xmlhttp = CreateObject("WinHttp.WinHttpRequest.5.1")
With Xmlhttp

.Open "GET", Url, False
.send

cmkey = Split(Split(.responsetext, "title='基本資料' cmkey='")(1), "'>基本資料<")(0)
cmkey = UrlEncode(cmkey)

Url_a = "https://www.cmoney.tw/finance/ashx/mainpage.ashx?action=GetStockListLatestSaleData&stockId=" & stock & "&cmkey=" & cmkey & "&_=" & UNIXTime
.Open "GET", Url_a, False
.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
.setRequestHeader "Referer", Url
.send

Set Json = Jsondata.JsonParse(.responsetext)

Cells(1, 1) = "股價" & CallByName(CallByName(Json, "commSaleData", VbGet), "SalePr", VbGet)
Cells(2, 1) = "股本(百萬)" & CallByName(CallByName(Json, "companyInfo", VbGet), "Capital", VbGet)
'================

'其它資料請自行用callbyname取出



'================


Url_b = "https://www.cmoney.tw/finance/ashx/mainpage.ashx?action=GetStockBasicInfo&stockId=" & stock & "&cmkey=" & cmkey
.Open "GET", Url_b, False
.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
.setRequestHeader "Referer", Url
.send

Set Json = Jsondata.JsonParse(Replace(Replace(.responsetext, "[", ""), "]", ""))

Cells(5, 1) = "單月營收年成長率:" & CallByName(Json, "MonthlyRevenueYearGrowth", VbGet)
Cells(6, 1) = "股價淨值比:" & CallByName(Json, "PBR", VbGet)


'================

'其它資料請自行用callbyname取出



'================



End With


Set Xmlhttp = Nothing
Set Json = Nothing
Set temp = Nothing

End Sub


Function UNIXTime()

UNIXTime = Round(((Date - #1/1/1970#) * 86400 + Timer) * 1000, 0)

End Function
'以下function因論譠語法關係,無法正常顯示,改用圖片,或參考附檔






如果嫌json解碼麻煩,請另找資料來源,或改用ie object ,但速度差了10倍以上

(20220505 補充:)
(因網頁改版,取消支援ie,下面ie object 範例失效,需改用上面json方式下載)


Sub Test()

Dim IE As Object, Url As String, table, i As Integer, j As Integer, temp

ActiveSheet.Cells.Clear
Application.ScreenUpdating = False

Set IE = CreateObject("InternetExplorer.Application")
Url = "https://www.cmoney.tw/finance/f00026.aspx?s=6706"

With IE
.Visible = True
.Navigate Url
Do While .Busy Or .ReadyState <> 4: DoEvents: Loop

Application.Wait (Now + TimeValue("0:00:5"))

Set table = .document.getelementsbytagname("table")(0).Rows
For i = 0 To table.Length - 1
For j = 0 To table(i).Cells.Length - 1
ActiveSheet.Cells(i + 1, j + 1) = table(i).Cells(j).innertext
Next j
Next i

Set table = .document.GetElementByID("HeaderContent")
temp = Split(table.innertext, vbNewLine)
For i = 0 To UBound(temp)
ActiveSheet.Cells(20 + i, 1) = temp(i)
Next i

ActiveSheet.Cells.Columns.AutoFit

End With

IE.Quit
Set IE = Nothing
Set table = Nothing

Application.ScreenUpdating = True

End Sub



(20210925) 網頁改版,需修正一行程式碼,請自行在附件裡面訂正)
(原)未改版前
cmkey = Right(Split(Split(.responsetext, "'>基本資料<")(1), "'>基本資料<")(0), 24)
改成如下
cmkey = Split(Split(.responsetext, "title='基本資料' cmkey='")(1), "'>基本資料<")(0)


(20220505) 網頁改版,需修正一行程式碼,請自行在附件裡面訂正)
(原)未改版前
cmkey = Split(Split(.responsetext, "title='基本資料' cmkey='")(1), "'>基本資料<")(0)
改成如下
cmkey = Split(Split(.responsetext, "基本資料' cmkey='")(1), "' page='")(0)



[點擊下載]
rachel0501
感謝樓主在20220505還願意更新資料!祝大大一生平安。
感謝樓主回復,這主要的資料網址(https://www.cmoney.tw/finance/ashx/mainpage.ashx?action=GetStockBasicInfo&stockId=" & stockid & "&cmkey=" & cmkey)我有找到,但為什麼po到瀏覽器或者使用postman這軟體(Content-Type及Referer都有設)來試,仍是會出現{"Error":-3,"Message":"金鑰不正確"},用vba卻抓得到資料?
tmwcykixe wrote:
但為什麼po到瀏覽器或者使用postman這軟體(Content-Type及Referer都有設)來試,仍是會出現{"Error":-3,"Message":"金鑰不正確"},用vba卻抓得到資料?(恕刪)


網站送出資料的流程大約如下:
一、進網站 https://www.cmoney.tw/finance/f00026.aspx?s=6706
二、產生金鑰
三、https://www.cmoney.tw/………GetStockBasicInfo&stockId=6706&cmkey=使用金鑰
四、金鑰沒錯,回傳json
五、網站整理好json,顯示頁面

vba 模擬流程大約如下:
a、進網站,拿金鑰
b、把金鑰給送出資料的網址
c、下載,excel整理

a=>b的過程(模擬一、二、三、四) ,在vba 中,簡單來說就是“沒有離開網頁
網站(https://www.cmoney.tw/finance/f00026.aspx?s=6706),當作使用者還在這一頁
金鑰不變,可正確下載資料

重點是有沒有離開網頁、重開網頁
離開,金鑰就失效
重開,金鑰就變

直接把送出資料的網址,放到瀏覽器、postman,重開、離開,都無法避免
金鑰一定會變,所以您怎麼試都不行
原來如此,我本以為vba送出2次send是上2次網站的意思耶。非常感謝樓主的釋疑。
另再請教樓主以下網站輸入代號後,如何得到真實的網址?
https://www.rocketfinancial.com
例如,當我輸入aapl,,網址顯示的是
https://www.rocketfinancial.com/Financials.aspx?fID=4614&pw=152220
這網址是如何取得?以利該網頁內資料的取得。
tmwcykixe wrote:
https://www.rocketfinancial.com/Financials.aspx?fID=4614&pw=152220
這網址是如何取得?以利該網頁內資料的取得。(恕刪)


aapl fid=4614、pw =152220,看起來是定值,寫在網址裡就行
21樓範例可簡單處理,table 位置請自行測試




不過,如果是圖表內的資料,就複雜一點了
send 的參數是用json格式
RequestHeader 也要設為 json格式







'a欄13碼數字,請自行轉成日期,可回頭找其它範例,或 google unixtime 用函數處理
Sub GET_rocketfinancial_json()

Dim Xmlhttp As Object, URL As String, Url_a As String, stock As String, PostJson As String, code As String
Dim Jsondata As Object, Json, temp

Set Jsondata = CreateObject("HtmlFile")
Jsondata.write ”<script>document.JsonParse=function (s) {return eval(’(’ + s + ’)’);}</script>”
'jsondata.write 這行是全形字,請自行改成半形


Sheets("工作表1").Cells.Clear

stock = "aapl"


URL = "https://www.rocketfinancial.com/"
Url_a = "https://www.rocketfinancial.com/WebService.asmx/SearchForFiler"
PostJson = "{""prefixText"":""" & stock & """,""count"":9}"


Set Xmlhttp = CreateObject("WinHttp.WinHttpRequest.5.1")
With Xmlhttp

.Open "POST", Url_a, False
.setRequestHeader "Content-type", "application/json"
.setRequestHeader "Accept", "application/json"
.setRequestHeader "Referer", URL
.send PostJson

Set Json = Jsondata.JsonParse(.responsetext)
Set Json = Jsondata.JsonParse(CallByName(Json, "d", VbGet))
code = CallByName(Json, "Second", VbGet)

URL = "https://www.rocketfinancial.com/Overview.aspx/GetData"
Url_a = "https://www.rocketfinancial.com/Overview.aspx?fID=" & code & "&pw=152220"
PostJson = "{ 'fID': '" & code & "', 'range': '730' }"

.Open "POST", URL, False
.setRequestHeader "Content-type", "application/json"
.setRequestHeader "Accept", "application/json"
.setRequestHeader "Referer", Url_a
.send PostJson

Set Json = Jsondata.JsonParse(.responsetext)

For i = 0 To CallByName(CallByName(Json, "d", VbGet), "length", VbGet) - 1
Set temp = CallByName(CallByName(Json, "d", VbGet), i, VbGet)
Cells(i + 1, 1) = temp.Date
Cells(i + 1, 2) = temp.Price
Next i

End With


Set Xmlhttp = Nothing
Set Jsondata = Nothing
Set Json = Nothing
Set temp = Nothing

End Sub


再次感謝樓的的回復,,,
sorry,我沒說清楚我的原意.,不過樓主的回復還是有很大的幫助。
參考上篇樓主回復有關cmoney的答案,我想到了這資料網址可從網頁原始碼取得,如
輸入amzn可得fID=6337、pw=209079,輸入aapl可得 fid=4614、pw =152220,其他參酌樓主回復,但該網頁不知為何輸入幾次後就會跳出登錄畫面,這點不知樓主有解方嗎?
tmwcykixe wrote:
原來如此,我本以為vba送出2次send是上2次網站的意思耶。...(恕刪)


以下這樣就像是在網頁裡點來點去
with xml
.send
.send
end with


以下這樣,就是重開2次
with xml
.send
end with
set xml=nothing
with xml
.send
end with


tmwcykixe wrote:
如輸入amzn可得fID=6337、pw=209079,輸入aapl可得 fid=4614、pw =152220(恕刪)


從網頁原始碼可知 fid 需向網站查詢,而 pw=((fid*11)-14)*3



請參考756樓,範例中的code 變數,就是 fid
再把code 變數代入 pw=((fid*11)-14)*3,可得pw值





tmwcykixe wrote:
但該網頁不知為何輸入幾次後就會跳出登錄畫面,這點不知樓主有解方嗎?(恕刪)


不知道,我不寫只有會員能用的範例
我一向只測試網站的開放資料,測試時沒出現這個問題(未登入)
用vba測試連續查詢,也沒出現擋ip的情形
請教樓主
這幾天http://mis.twse.com.tw常常出現誤無法取得資料
不知道問題是出在哪裡?
看來證交所這支 stock/api/getStockInfo.jsp API
隨著逐筆交易制度得改變已經沒有可以用的資料可以參考了
最重要的 z 欄位有時候會傳回 - 符號,所以沒辦法推算目前的成交價格


{"queryTime":{"stockInfoItem":1985,"sessionKey":"tse_9904.tw_20200323|","sessionStr":"UserSession","sysDate":"20200323","sessionFromTime":-1,"stockInfo":1010361,"showChart":false,"sessionLatestTime":-1,"sysTime":"11:37:29"},"referer":"","rtmessage":"OK","exKey":"if_tse_9904.tw_zh-tw.null","msgArray":[{"n":"寶成","g":"10_12_29_21_71_","u":"25.6500","mt":"459509","o":"23.0000","ps":"251","tk0":"9904.tw_tse_20200323_B_9999005267","a":"23.7500_23.8000_23.8500_23.9000_23.9500_","tlong":"1584934641000","t":"11:37:21","it":"12","ch":"9904.tw","b":"23.7000_23.6500_23.6000_23.5500_23.5000_","f":"4_51_160_211_70_","w":"21.0500","pz":"23.0500","l":"22.2500","c":"9904","v":"6175","d":"20200323","tv":"-","tk1":"9904.tw_tse_20200323_B_9999004900","ts":"0","nf":"寶成工業股份有限公司","y":"23.3500","p":"0","i":"20","ip":"0","z":"-","s":"-","h":"23.9500","ex":"tse"}],"userDelay":5000,"rtcode":"0000","cachedAlive":358}
關閉廣告
文章分享
評分
評分
複製連結
請輸入您要前往的頁數(1 ~ 144)

今日熱門文章 網友點擊推薦!