Board logo

標題: [發問] 網頁資料很長,如何有效率地知道已完整進來 [打印本頁]

作者: Scott090    時間: 2017-11-12 16:59     標題: 網頁資料很長,如何有效率地知道已完整進來

本帖最後由 Scott090 於 2017-11-12 17:01 編輯

'捲動網頁
'''' i 值太小,網頁資料會來不及進來;太大會浪費時間
''''   有何方法可以知道資料已進來齊全而停止;或其他方式取代本方法?
            i = 0
            While i < 50
                .Document.Parentwindow.scrollby 0, 10000 'Move,Scroll IE window down to bottom
                i = i + 1
            Wend

請問那一位前輩幫忙? 先謝謝

以下的例子是資料的長短多寡取決於日期期間的長短,如何做會比較有效率?
  1. '使用 ie,Application 物件
  2. '從 finance.Yahoo.com取得歷史資料
  3. '
  4. Sub getHistoricalData()
  5.         Dim Code
  6.         Code = "AAPL"
  7.         Const mysteryNum = 2209190400#
  8.         Dim ie, DATAar, A$, yyDate
  9.         Dim URL As String
  10.         Dim StartDate, EndDate, timer, tt As Date
  11.         Dim Table As Object, oDoc As Object
  12.         Dim i%, j%, k%
  13.         
  14.         StartDate = "1999/1/2"            '開始日期
  15.         EndDate = Date                          '結束日期,預設為今天

  16.       '轉換為秒鐘數字
  17.     StartDate = DateValue(StartDate) * 86400 - mysteryNum
  18.     EndDate = DateValue(EndDate) * 86400 - mysteryNum
  19.    
  20.    Set ie = CreateObject("InternetExplorer.Application")
  21.         
  22.     With ie
  23.             Application.StatusBar = "打開網頁,等待資料備齊 ....."
  24.             URL = "https://finance.yahoo.com/quote/" & Code & "/history?period1=" & StartDate & "&period2=" & EndDate & "&interval=1d&filter=history&frequency=1d"
  25.             .Visible = True ' False                '顯示 IE否?
  26.             .navigate URL
  27.             Application.Wait Time + #12:00:04 AM#                   '等候網頁4秒鐘
  28.             tt = Time + #12:00:05 AM#
  29.             Do While (.busy Or .readyState <> 4) And Time < tt
  30.                 DoEvents
  31.             Loop
  32.             
  33.             '捲動網頁
  34. '''' i 值太小,網頁資料會來不及進來;太大會浪費時間
  35. ''''   有何方法可以知道資料已進來齊全而停止;或其他方式取代本方法?
  36.             i = 0
  37.             While i < 50
  38.                 .Document.Parentwindow.scrollby 0, 10000 'Move,Scroll IE window down to bottom
  39.                 i = i + 1
  40.             Wend
  41.                         
  42.             Application.StatusBar = "取網頁資料中 .... "
  43.             Set oDoc = .Document.getElementsByTagName("TABLE")(1)
  44.             
  45.             ActiveSheet.Cells.Clear
  46.             ReDim DATAar(oDoc.Rows.Length - 1, 7)
  47.             
  48.             For i = 0 To oDoc.Rows.Length - 2
  49.                     For j = 0 To 6
  50.                           On Error Resume Next
  51.                           DATAar(i + 1, j + 1) = oDoc.Rows(i).Cells(j).innertext
  52.                           If j = 0 And i <> 0 Then
  53.                           
  54.                           ''''    yyDate = CDate("Oct 01, 2017")
  55.                                 A = DATAar(i + 1, j + 1)
  56.                                 A = Mid(A, 2, 3) & " " & Mid(A, 8, 2) & ", " & Right(A, 4)
  57.                                 yyDate = CDate(A)
  58.                                 DATAar(i + 1, j + 1) = yyDate
  59.                                 
  60.                           End If
  61.                     Next
  62.             Next
  63.             Application.StatusBar = "資料移到Excel 工作表 ....."
  64.             ActiveSheet.Cells(1, 1).Resize(UBound(DATAar), 7).Value = DATAar
  65.             Columns("A:A").NumberFormatLocal = "yyyy/mm/dd"
  66.             Columns("G:G").NumberFormatLocal = "#,##0_)"
  67.             .Quit
  68.     End With
  69.     Application.StatusBar = "資料下載完成 ....... "
  70.     Application.Wait Time + #12:00:02 AM#
  71.     Application.StatusBar = False
  72.    
  73. End Sub
複製代碼

作者: GBKEE    時間: 2017-11-13 07:18

本帖最後由 GBKEE 於 2017-11-14 15:24 編輯

回復 1# Scott090
  1. Option Explicit
  2. Dim Sh As Worksheet
  3. Sub Ex_網頁底部()
  4.     Dim E As Object, Er As Integer
  5.     'Dim Timer As Date   'Timer 為vba的內建函數 ,變數名稱盡量不要相同
  6.     Dim xTimer As Date
  7.     Application.DisplayStatusBar = True
  8.     Application.StatusBar = False
  9.     Set Sh = ActiveSheet
  10.     Sh.Cells.Clear
  11.     On Error GoTo EE
  12.     With CreateObject("InternetExplorer.Application")
  13.       '  .Visible = True
  14.         xTimer = Time
  15.         .Navigate "https://finance.yahoo.com/quote/AAPL/history?period1=915206400&period2=1505174400&interval=1d&filter=history&frequency=1d"
  16.         Do While .Busy Or .readyState <> 4: DoEvents: Application.StatusBar = "******  等 候 網 頁 下... " & Time:   Loop
  17.         Do
  18.              Application.StatusBar = "******  資料 下載中..." & Application.Text(Time - xTimer, "   [S]秒") & " ******"
  19.             .document.Parentwindow.scrollBy 0, 37900
  20.             Do While .Busy Or .readyState <> 4: DoEvents:            Loop
  21.             With .document.documentElement
  22.                 ' Debug.Print .scrollTop , .clientHeighT, .scrollHeight  '***計算出 37900為最大值
  23.                 If .scrollTop + .clientHeighT = .scrollHeight Then Exit Do
  24.             End With
  25.             DoEvents
  26.         Loop
  27.         Set E = .document.ALL.TAGS("TABLE")(1)
  28.         Ep .document.ALL.TAGS("TABLE")(1).outerHTML
  29.         Application.StatusBar = "** [" & xTimer & " - " & Time & Application.Text(Time - xTimer, " ] , 計 [S]秒") & " ,下載 共 " & E.Rows.Length - 2 & " 筆資料 完畢 !! **"
  30.         .Quit        '關閉網頁
  31.     End With
  32. Exit Sub
  33. EE:  '程式運行速度大於ie時的措施
  34.     Application.StatusBar = "網頁錯誤等候中...."
  35.     Er = Er + 1
  36.     If Er >= 3 Then Stop
  37.     Application.Wait (Second(Now()) + 2)
  38.     Resume
  39. End Sub
  40. Private Sub Ep(S As String) ' A(A.Length - 1).outerHTML
  41.     With CreateObject("InternetExplorer.Application")
  42.         .Navigate "about:Tabs"
  43.        ' .Visible = True
  44.         .document.body.innerHTML = S
  45.         .ExecWB 17, 2       '  Select All
  46.         .ExecWB 12, 2       '  Copy selection
  47.         With Sh
  48.             .Activate
  49.            ' .Cells.Clear
  50.             .Range("A1").Select
  51.             .PasteSpecial Format:="HTML", Link:=False, DisplayAsIcon:=False, NoHTMLFormatting:=True
  52.             .Range("A1").Select
  53.         End With
  54.         .Quit
  55.     End With
  56. End Sub
複製代碼

作者: Scott090    時間: 2017-11-13 15:57

本帖最後由 Scott090 於 2017-11-13 16:01 編輯

回復 2# GBKEE


  謝謝  GBKEE 大的指導
為觀察網頁行為特性將兩種方法做一比較,執行結果如下表:
設定欲取資料期間;開始 1999/1/2, 結束期間 2017/9/12       
[attach]27961[/attach]

其中方法二並未完整的取得資料;
方法一則視 scrollby 的參數而定,設小了取資料不完整,設大了資料可以完整取得但有空轉的時間
謝謝
  1. Sub Ex_網頁底部()
  2.     Dim E As Object, R As Long, C As Long, i%
  3.     Dim timer As Date
  4.     'period1 = 1483286400     '2017/1/2
  5.     'period1 = 1451664000    '2016/1/2
  6.     'period1 = 915206400      '1999/1/2
  7.     'period2 = 1505174400     '2017/9/12

  8.     With CreateObject("InternetExplorer.Application")
  9.         .Visible = True
  10.         .Navigate "https://finance.yahoo.com/quote/AAPL/history?period1=915206400&period2=1505174400&interval=1d&filter=history&frequency=1d"
  11.         Do While .Busy Or .readyState <> 4: DoEvents: Loop
  12.         Set E = .document.ALL.TAGS("TR")
  13.        i = 0
  14.        timer = Time
  15.         Do
  16.             i = i + 1
  17.            With .document
  18. '方法一:
  19. '                .Parentwindow.scrollBy 0, 500  '改變 y 點數做試驗
  20. '                With .DocumentElement
  21. '                    R = R + .clientheight
  22. '                    Debug.Print "捲動次數:" & i, "R:" & R, "SH: " & .scrollHeight ', "CH: " & .clientheight
  23. '                    If R - .clientheight > .scrollHeight Then Exit Do
  24. '                End With
  25. '==============================================================
  26. '方法二:
  27.                   .Parentwindow.scrollBy 0, .DocumentElement.scrollHeight
  28.                   R = R + .DocumentElement.scrollHeight
  29.                   Debug.Print "捲動次數:" & i, "R:" & R, "SH: " & .DocumentElement.scrollHeight
  30.                   If R - .DocumentElement.scrollHeight > .DocumentElement.scrollHeight Then Exit Do
  31. ''''==============================================================
  32.                   
  33.             End With
  34.             DoEvents
  35.         Loop
  36.         
  37.         Debug.Print "時程: " & (Time - timer) * 86400
  38.         
  39.         ActiveSheet.Cells.Clear
  40.         For R = 1 To E.Length - 1
  41.             For C = 0 To E(R).Cells.Length - 1
  42.                 Cells(R, C + 1) = E(R).Cells(C).INNERTEXT
  43.             Next
  44.         Next
  45.         .Quit        '關閉網頁
  46.     End With
  47.     MsgBox "Ok"
  48. End Sub
複製代碼

作者: GBKEE    時間: 2017-11-14 15:27

回復 3# Scott090

參考這裡  http://www.jb51.net/article/57614.htm
2# 的程式碼修改了為
  1. With .document.documentElement
  2.                 ' Debug.Print .scrollTop , .clientHeighT, .scrollHeight  '***計算出 37900為最大值
  3.                 If .scrollTop + .clientHeighT = .scrollHeight Then Exit Do
  4.             End With
複製代碼
但測試時,.偶爾還是不能完全下載,有待努力
作者: Scott090    時間: 2017-11-14 21:41

回復 4# GBKEE


    GBKEE大:
謝謝進一步的解答與教導 及提供的參考的網址
將繼續地瞭解與研究

感恩
作者: Scott090    時間: 2017-11-16 18:13

回復 4# GBKEE

從參考的網址內的各個變數,  
scrollHeight,  scrolltop,  offsetheight, clientHeight, body.clientheight .....
沒找出確實的 滾動數字相互之間的穩定關係,造成 激發滾動迴圈的不穩定性 及 取得的資料不一定 是底部最後一筆;
而,欲取得的資料格式是可以既知,所以改用 "是否最後一筆資料" 來決定滾動迴圈

把程式碼修飾如下:
增加 日期 變數 Dim startDate as date,  A

startdate = #1999/1/2#

'跳出迴圈條件 If .scrolltop + .clientHeight = .scrollHeight Then exit do 改成
A = E(E.Length - 2).Cells(0).INNERTEXT
If CDate(Mid(A, 2, 3) & " " & Mid(A, 8, 2) & ", " & Right(A, 4)) - startDate < 5 Then Exit Do

測試結果是穩定的
作者: GBKEE    時間: 2017-11-19 10:53

回復 6# Scott090
不錯的這樣就可以得到完整資料.
程式執行時間大約需一分鐘,我整理一下在狀態列上加上資訊.
  1. Option Explicit
  2. Dim Sh As Worksheet
  3. Dim xTimer As Date
  4. 'Dim Timer As Date   'Timer 為vba的內建函數 ,變數名稱盡量不要相同
  5. Sub Ex_網頁底部()
  6.     Dim E As Object, Ie_Date As Date, i As Integer
  7.     Application.DisplayStatusBar = True
  8.     Application.StatusBar = False
  9.     Set Sh = ActiveSheet
  10.     Sh.Cells.Clear
  11.     On Error GoTo EE
  12.     With CreateObject("InternetExplorer.Application")
  13.         '.Visible = True
  14.         xTimer = Time
  15.         .Navigate "https://finance.yahoo.com/quote/AAPL/history?period1=915206400&period2=1505174400&interval=1d&filter=history&frequency=1d"
  16.         Do While .Busy Or .readyState <> 4: DoEvents: Application.StatusBar = "******  等 候 網 頁 下....★★★" & GetTime:  Loop
  17.         Ie_Date = Getdate(.document.ALL.TAGS("INPUT")(4).Value)
  18.         Set E = .document.ALL.TAGS("tr")
  19.        Do
  20.             Application.StatusBar = "★★★★★  資料 下載中..." & GetTime & String(Val(GetTime), "★")
  21.             .document.Parentwindow.scrollby 0, 37900
  22.            ' Do While .Busy Or .readyState <> 4: DoEvents:            Loop
  23.            If Getdate(E(E.Length - 2).Cells(0).innertext) - Ie_Date < 5 Then Exit Do
  24.             DoEvents
  25.         Loop
  26.         Set E = .document.ALL.TAGS("TABLE")(1)
  27.         
  28.         Ep .document.ALL.TAGS("TABLE")(1).outerHTML
  29.         Application.StatusBar = "** ★" & xTimer & " - " & Time & "★" & GetTime & " ,下載 共 " & E.Rows.Length - 2 & " 筆資料 完畢 !! **"
  30.         .Quit        '關閉網頁
  31.     End With
  32.     With Sh
  33.         For i = 2 To .Range("A1").End(xlDown).Row - 1
  34.             .Range("A" & i) = Getdate(.Range("A" & i))
  35.         Next
  36.         .Range("A:A").NumberFormatLocal = "yyyy/mm/dd"
  37.     End With
  38.    
  39. Exit Sub
  40. EE:  '程式運行速度大於ie時的措施
  41.     Application.StatusBar = "網頁錯誤等候中....★★★ " & GetTime
  42.     Application.Wait (Second(Now()) + 2)
  43.     Resume
  44. End Sub
  45. Private Sub Ep(S As String)
  46.     With CreateObject("InternetExplorer.Application")
  47.         .Navigate "about:Tabs"
  48.        ' .Visible = True
  49.         .document.body.innerHTML = S
  50.         .ExecWB 17, 2       '  Select All
  51.         .ExecWB 12, 2       '  Copy selection
  52.         With Sh
  53.             .Activate
  54.            ' .Cells.Clear
  55.             .Range("A1").Select
  56.             .PasteSpecial Format:="HTML", Link:=False, DisplayAsIcon:=False, NoHTMLFormatting:=True
  57.             .Range("A1").Select
  58.         End With
  59.         .Quit
  60.     End With
  61. End Sub
  62. Private Function Getdate(sDate As String) As Date
  63.     Dim A As String, b As Integer
  64.     A = Split(sDate, "-")(0)
  65.     b = AscW(Mid(A, 1, 1))
  66.     A = Replace(A, ChrW(b), " ")
  67.     A = Replace(A, "?", "")
  68.     Getdate = CDate(A)
  69. End Function
  70. Private Function GetTime() As String
  71.     GetTime = Application.Text(Time - xTimer, "   [S]秒")
  72. End Function
複製代碼

作者: quickfixer    時間: 2017-11-19 18:40

我在01文書處理區有看到只要1.8秒的程式碼
作者: Scott090    時間: 2017-11-20 07:27

回復 7# GBKEE


    GBKEE 大大:
謝謝你的總結
作者: Scott090    時間: 2017-11-20 07:31

回復 8# quickfixer


   
我在01文書處理區有看到只要1.8秒的程式碼


請把網址貼出來,讓大家參考
謝謝
作者: quickfixer    時間: 2017-11-20 10:25

本帖最後由 quickfixer 於 2017-11-20 10:27 編輯

不好意思我還不能貼url沒有權限
去看就知道是那篇文章了
在文書處理區的第一頁
文章内11/16號那個程式
作者: Scott090    時間: 2017-11-20 21:23

回復 11# quickfixer


參考網址:   https://www.mobile01.com/topicdetail.php?f=511&t=4737630&p=28
這個是直接下載 .csv 檔
謝謝提供的信息
作者: quickfixer    時間: 2017-11-21 02:24

回復 12# Scott090


  多了一篇不下載csv,只下載網頁的程式碼
比較慢每個股票資料要8.91秒下載
那篇文章每個程式都很快,可是有點難
作者: Scott090    時間: 2017-11-28 07:40

回復 13# quickfixer


    這個麻辣家族論壇也有使用 xmlhttp 供參考的例子,
    搜索一下就有了
作者: quickfixer    時間: 2018-2-2 00:26

回復 14# Scott090

我知道有一些範例可搜尋到,可是很分散
那串文章寫了各大網站的下載範例很集中,而且新手也可以下載:lol
另外您在問的,鉅亨網歷史行情下載問題
01那邊75樓的文章可解決
不好意思權限還不夠,只能在這發言
作者: Scott090    時間: 2018-2-2 08:39

回復 15# quickfixer


    謝謝提供的信息
去年有去瀏覽過




歡迎光臨 麻辣家族討論版版 (http://forum.twbts.com/)