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

snare 大大
想請問一下, 如果XMLHTTP遇到timeout可以怎麼解決?
With GetXml
.Open "GET", URL, False
.setRequestHeader "Cache-Control", "no-cache"
.setRequestHeader "Pragma", "no-cache"
.setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
.send
因為網路的問題, 程式常常會卡在.send的地方
試著用https://stackoverflow.com/questions/11407010/how-to-vba-callback-function-when-xmlhttp-ontimeout
的方法, 但好像沒用??
我是改成下面這樣
If GetXml.Status = "200" Then
HTMLsourcecode.body.innerhtml = .responsetext
ElseIf GetXml.Status = "408" Then
Application.Wait Now() + TimeValue("00:00:10")
GoTo retry
Else
End If
有辦法讓VBA偵測到timeout然後隔幾秒重試個幾次, 超過次數在exit嗎??

另外有個問題想請問, 我VBA會讀取清單去開啟檔案做更新(約10幾個table), 然後儲存關閉, 直到清單的檔案都開啟更新完畢為止
之前使用webrequst的方式, 他會一直跑至少跑幾百個才會停住, 現在改用XMLHTTP的方式都是跑10-30次就停止了, 請問您知道可能是什麼問題嗎?

謝謝
snare 大大
想請問一下, 如果XMLHTTP遇到timeout可以怎麼解決?
With GetXml
.Open "GET", URL, False
.setRequestHeader "Cache-Control", "no-cache"
.setRequestHeader "Pragma", "no-cache"
.setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
.send
因為網路的問題, 程式常常會卡在.send的地方
試著用https://stackoverflow.com/questions/11407010/how-to-vba-callback-function-when-xmlhttp-ontimeout
的方法, 但好像沒用??
我是改成下面這樣
If GetXml.Status = "200" Then
HTMLsourcecode.body.innerhtml = .responsetext
ElseIf GetXml.Status = "408" Then
Application.Wait Now() + TimeValue("00:00:10")
GoTo retry
Else
End If
有辦法讓VBA偵測到timeout然後隔幾秒重試個幾次, 超過次數在exit嗎??

另外有個問題想請問, 我VBA會讀取清單去開啟檔案做更新(約10幾個table), 然後儲存關閉, 直到清單的檔案都開啟更新完畢為止
之前使用webrequst的方式, 他會一直跑至少跑幾百個才會停住, 現在改用XMLHTTP的方式都是跑10-30次就停止了, 請問您知道可能是什麼問題嗎?

謝謝
rainbowsperm wrote:
因為網路的問題, 程式常常會卡在.send的地方
試著用https://stackoverflow.com/questions/11407010/how-to-vba-callback-function-when-xmlhttp-ontimeout
的方法, 但好像沒用??


比起檢查timeout,不如直接檢查有沒有資料

rainbowsperm wrote:
有辦法讓VBA偵測到timeout然後隔幾秒重試個幾次, 超過次數在exit嗎??


可利用on error 計算次數

rainbowsperm wrote:
另外有個問題想請問, 我VBA會讀取清單去開啟檔案做更新(約10幾個table), 然後儲存關閉, 直到清單的檔案都開啟更新完畢為止
之前使用webrequst的方式, 他會一直跑至少跑幾百個才會停住, 現在改用XMLHTTP的方式都是跑10-30次就停止了, 請問您知道可能是什麼問題嗎?
謝謝


每次都10~30次停住,如果不是程式沒寫好,就是被網站暫時擋ip
網址???
webrequst因為慢,所以不容易被擋
xmlhttp因為非常快,只要網站有限制查詢,一下就被擋了

就像,基本市況報導網站(https://mis.twse.com.tw/stock/index.jsp),就有限制
約20次左右,就被擋了,所以在部份網站使用xmlhttp下載,需適當的加入延遲時間

可加入on error檢查Err.Description訊息,決定處理方式


解決方式一:
直接用on error resume next,跳過所有錯誤,再回頭檢查沒下載完的資料
可參考272樓範例

解決方式二:
利用Application.OnTime Now排程(偽多工),延後下載,可再加on error計算重試次數
某一筆排程如果卡住,也不會影響其它排程
可參考219、686樓範例


但利用排程要注意程式碼的寫法

Sub test()

'假設a1~a30是股票代號
For i = 1 To 30
Delaytick (0.5)
'延遲0.5秒,建議可改亂數
If i > 15 Then
'超過15次,改排程下載
Application.OnTime Now + TimeSerial(0, 0, 10), "'Get_xml " & """" & Cells(i, 1) & """" & "," & i & "'"
'排程10秒後再執行下載,建議可改亂數
'Get_xml 後面必需加上一個空格,字串需加上",數字不用,前後需加上'

Else
Call Get_xml(Cells(i, 1), i)
End If
Next i


End Sub


Sub Get_xml(stock_id As String, lastrow As Integer)

re = 0
retry:
On Error GoTo Error_debug

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


'下載用程式碼放這裡


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

Exit Sub

Error_debug:
re = re + 1

Delaytick (1.3)
If re > 3 Then
'大於3次結束程式
Debug.Print "error"
re = 0
Exit Sub
End If

If Err.Number <> 0 Then
'列出錯誤訊息,或利用不同的錯誤訊息,決定程式的處理方式
Debug.Print "Get_xml:" & Err.Description
End If

On Error GoTo -1
Err.Clear

GoTo retry

End Sub

Sub Delaytick(setdelay As Single)

Dim StartTime As Double, NowTime As Double
StartTime = Timer * 100
setdelay = setdelay * 100
Do
NowTime = Timer * 100
DoEvents
Loop Until NowTime - StartTime > setdelay

End Sub


snare wrote:
比起檢查timeout(恕刪)


非常感謝snare大大超迅速的回覆, 感覺大大一起床就瞬間回覆了~~
我有每隔約10秒鐘更新一次,
也網站確定沒有被擋IP, 因瀏覽器網頁都還開得起來

請問如何偵測回傳有沒有資料, 可以這樣寫嗎?
redownload:
With GetXml
.Open "GET", URL, False
.setRequestHeader "Cache-Control", "no-cache"
.setRequestHeader "Pragma", "no-cache"
.setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
.send

if HTMLsourcecode.body.innerhtml = "" then
........
Application.Wait Now() + TimeValue("00:00:10")
Goto redownload
End if
嗎?


因為是超級新手, 大部分的程式碼也都是用大大的程式碼下去修改的,
試了大大的回覆, 可惜還是無法完全參透~~~XD
不過看到一大堆的錯誤好像都是
Get_xml:沒有設定物件變數或 With 區塊變數

感覺這些錯誤沒關係??因為都可正確跑完, 只是跑久了就會卡住
關閉Excel再重開就可以再跑
程式有用到array不過也是參考大大的應該沒什問題才對,不知有沒有可能是電腦的關係??
https://www.dropbox.com/s/0o72inym1wme40p/debug.zip?dl=0

謝謝
Snare大大您好,

我是前一段時間在無意中發現您這篇寶貴的大樓, 自己慢慢地一再重讀與試作, 總算有一點點的認識.(由於不斷重讀,停頓與試作,迄今還未讀完).

目前在抓取"庫藏股清單"時, 碰到大部分資料無法抓到(用Debug.Print .responseText,即可發現),不知問題是出在哪裡?

'------------程式碼如下:
Sub 庫藏股清單()
Cells.Clear

Dim HTMLsourcecode, Url, Url_a, Url_b, Table, TempArray()
Set HTMLsourcecode = CreateObject("htmlfile")

Url = "https://mops.twse.com.tw/mops/web/ajax_t35sc09"
Url_a = "https://mops.twse.com.tw/mops/web/t35sc09"
Url_b = "encodeURIComponent=1&step=1&firstin=1&off=1&TYPEK=sii&d1=1090201&d2=1090424&RD=1"

With CreateObject("WinHttp.WinHttpRequest.5.1")
.Open "POST", Url, False
.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
.setRequestHeader "Referer", Url_a
.setRequestHeader "Cache-Control", "no-cache"
.setRequestHeader "Pragma", "no-cache"
.setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
.Send Url_b

HTMLsourcecode.body[removed] = convertraw(.responseBody) '.responseText, 試過,沒有亂碼的問題
Debug.Print .responseText
' -----執行到這裡,查看 .responsetext, 發覺大部分的原始資料,都沒有下載到,
' -----不知上面的程式碼,哪裡有錯 ?

' -----在上面問題,沒有解決前,以下的程式碼,只是先寫著,暫且沒有意義
' -----目前可以判斷的出來,資料的table不止一個(有15個,需再判斷何者有用),
' -----將來需增加迴圈來處理,改寫程式碼
Debug.Print HTMLsourcecode.all.tags("table").Length
Set Table = HTMLsourcecode.all.tags("table")(2).Rows
ReDim TempArray(Table.Length - 1, Table(2).Cells.Length - 1)

For i = 0 To Table.Length - 1
For j = 0 To Table(i).Cells.Length - 1
TempArray(i, j) = Table(i).Cells(j).innerText
Next j
Next i

End With

With Sheets("sheet1")
.Range(.Cells(1, 1), .Cells(Table.Length, Table(2).Cells.Length)) = TempArray()
End With

Set HTMLsourcecode = Nothing
Set Table = Nothing
Erase TempArray()

End Sub

'-----------------------------------------------------------------------
Function convertraw(rawdata)

Dim rawstr
Set rawstr = CreateObject("adodb.stream")

With rawstr
.Type = 1
.Mode = 3
.Open
.Write rawdata
.Position = 0
.Type = 2
.Charset = "utf-8"
convertraw = .ReadText
.Close
End With

Set rawstr = Nothing

End Function

最後很很感謝您無私的教導,與不求回報不厭其煩的回答問題.
更正補充
此行 HTMLsourcecode.body[removed] = convertraw(.responseBody) 我在copy時,不知為何
出現[removed], 我的原本程式碼在[removed]部分應該是如Snare大大常用的 "innerHTML"
rainbowsperm wrote:
請問如何偵測回傳有沒有資料, 可以這樣寫嗎?
(恕刪)
if HTMLsourcecode.body.innerhtml = "" then
(恕刪)


不行

rainbowsperm wrote:
不過看到一大堆的錯誤好像都是
Get_xml:沒有設定物件變數或 With 區塊變數
(恕刪)


一、同一個副程式裡面,同時用了on error goto 、on error resume
二、少一行



rainbowsperm wrote:
感覺這些錯誤沒關係??因為都可正確跑完, 只是跑久了就會卡住
關閉Excel再重開就可以再跑
(恕刪)


程式沒寫好
例如:下載財報()
不同的網址全部混在一個副程式裡面
on error resume、on error goto同時存在
這樣程式一出錯,根本不知道是那個網址的問題
建議重寫,不同網址全部獨立出來,改成下面這樣



Sub 下載財報(stock_id As String)

Application.ScreenUpdating = False

Call 下載年報(stock_id)
Call 下載季報(stock_id)
Call 下載損益年表(stock_id)
Call 下載損益季表(stock_id)
Call 下載資產負債年表(stock_id)
Call 下載資產負債季表(stock_id)
...
...
...
call ......
call ......

Application.ScreenUpdating = true

End Sub


每個副程式裡加上773樓的除錯寫法
除錯訊息,也要做好名稱提示
Debug.Print "下載年報:" & Err.Description
Debug.Print "下載損益年表:" & Err.Description
……
……
這樣才能知道是那個網址出錯
herricane5718 wrote:
目前在抓取"庫藏股清單"時, 碰到大部分資料無法抓到(用Debug.Print .responseText,即可發現),不知問題是出在哪裡?
' -----執行到這裡,查看 .responsetext, 發覺大部分的原始資料,都沒有下載到,
' -----不知上面的程式碼,哪裡有錯 ?

' -----在上面問題,沒有解決前,以下的程式碼,只是先寫著,暫且沒有意義
' -----目前可以判斷的出來,資料的table不止一個(有15個,需再判斷何者有用),
' -----將來需增加迴圈來處理,改寫程式碼


程式沒錯…錯在您搞錯了除錯視窗(即時運算視窗)的用法
除錯視窗只適合檢查少量資料,有字數限制,超過不顯示
要檢查全部資料,請丟到工作表裡面
cells(1,1)=.responsetext



可改用msxml2,會比5.1快一點








Sub get_twse()

Dim Url As String, Url_a As String, Url_b As String, HTMLsourcecode As Object, GetXml As Object, i As Integer, j As Integer, k As Integer, lastrow As Integer
Set HTMLsourcecode = CreateObject("htmlfile")
Set GetXml = CreateObject("msxml2.xmlhttp")

Url = "https://mops.twse.com.tw/mops/web/ajax_t35sc09"
Url_a = "https://mops.twse.com.tw/mops/web/t35sc09"
Url_b = "encodeURIComponent=1&step=1&firstin=1&off=1&TYPEK=sii&d1=1090204&d2=1090429&RD=1"

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

With GetXml
.Open "POST", Url, False
.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
.setRequestHeader "Referer", Url_a
.setRequestHeader "Cache-Control", "no-cache"
.setRequestHeader "Pragma", "no-cache"
.setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
.send (Url_b)


HTMLsourcecode.body.innerhtml = .responsetext
lastrow = 0

For k = 0 To HTMLsourcecode.all.tags("table").Length - 1

Set Table = HTMLsourcecode.all.tags("table")(k).Rows
For i = 0 To Table.Length - 1
lastrow = lastrow + 1
For j = 0 To Table(i).Cells.Length - 1
ActiveSheet.Cells(lastrow, j + 1) = Table(i).Cells(j).innertext
Next j
Next i

Next k

End With

Sheets("工作表1").Columns.AutoFit

Set HTMLsourcecode = Nothing
Set GetXml = Nothing
Set Table = Nothing

End Sub
Snare大大,

謝謝您的說明並幫我先將回圈部分完成. 不勝感激 ,已測試,ok!
感謝Snare大大的建議,
已將每個網址都獨立一個sub出來, 果真這樣比較容易debug....XD
不過測試後單獨跑都沒出現錯誤
但讀清單跑, 也沒發生錯誤訊息, 但跑了20-30檔, EXCEL就一樣沒反應~~試過重裝excel也不行~~
不知是否還有其他建議~~~><

https://www.dropbox.com/s/wztzpe9jnq1wvy8/debug.rar?dl=0

感謝
關閉廣告
文章分享
評分
評分
複製連結
請輸入您要前往的頁數(1 ~ 144)

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