Board logo

標題: [發問] vba 操作ie匯入資料 [打印本頁]

作者: randomwalk    時間: 2013-5-17 06:02     標題: vba 操作ie匯入資料

各位好
請問能以vba 開啟以下網址並完成
http://mops.twse.com.tw/mops/web/t164sb04
1.最新資料改成歷史資料
2.公司代號輸入2330
3.年度102
4.選第一季
並在查詢出資料後匯入excel,

因為今年度IFRS上路後,公開資訊站大改版,原本可以用http語法查詢出個別公司報表,
望網兄不吝指教,感謝
作者: GBKEE    時間: 2013-5-19 15:17

本帖最後由 GBKEE 於 2013-5-19 15:36 編輯

回復 1# randomwalk
這網頁: 無論是[最新資料] 或 [歷史資料] 的資料都一樣???
  1. Sub Ex()
  2.     Dim i As Integer, s As Integer, k As Integer, A, ii, j
  3.     Dim co_id As String, isnew As String, season As String
  4.     co_id = InputBox("請輸入 公司代號")
  5.     If Not IsNumeric(Val(co_id)) Or Len(co_id) <> 4 Then Exit Sub              '不是四位數的數字
  6.     isnew = InputBox("1:最新資料,2:歷史資料" & vbLf & "請選 1 , 2")
  7.     If isnew <> "1" And isnew <> "2" Then Exit Sub                              '沒選1 或 2
  8.     If isnew = "2" Then season = InputBox("輸入年度 , 季別" & vbLf & "例 101,01")
  9.                                     '第一季 01,第二季 02第三季 03,第四季 04.
  10.     With CreateObject("InternetExplorer.Application")
  11.         .Visible = True
  12.         .Navigate "http://mops.twse.com.tw/mops/web/t164sb04"
  13.         Do While .Busy Or .ReadyState <> 4: DoEvents: Loop
  14.         With .document
  15.             For Each A In .getelementsbytagname("INPUT")
  16.                 If A.Name = "co_id" Then A.Value = co_id
  17.             Next
  18.             For Each A In .getelementsbytagname("SELECT")
  19.                 If A.Name = "isnew" Then
  20.                     A.Value = True
  21.                     If isnew = "2" Then
  22.                         A.Focus
  23.                         Application.Wait Now + #12:00:02 AM#
  24.                         Application.SendKeys "{DOWN}"
  25.                         Application.Wait Now + #12:00:02 AM#
  26.                         Application.SendKeys "{ENTER}"
  27.                     End If
  28.                 End If
  29.                 If A.Name = "year" And isnew = "2" Then A.Value = Split(season, ",")(0)
  30.                 If A.Name = "season" And isnew = "2" Then A.Value = Split(season, ",")(1)
  31.             Next
  32.             For Each A In .getelementsbytagname("INPUT")
  33.                 If Trim(A.Value) = "搜尋" And A.Name <> "rulesubmit" Then A.Click        '按下[搜索]鍵
  34.             Next
  35.         End With
  36.         Application.Wait Now + #12:00:10 AM#                     '等待網頁下載資料
  37.         Set A = .document.getelementsbytagname("table")
  38.         On Error Resume Next       '***有些table沒Rows資料會產生錯誤 不理會它,程式繼續走
  39.         With ActiveSheet
  40.             .Cells.Clear
  41.            '************************
  42.            ' For ii = 0 To A.Length - 1        '不知道table範圍在何處: 從0開始
  43.            '******************************
  44.             For ii = 11 To A.Length - 1        ''從11開始 用 Debug.Print ii  找出所要資料的table範圍
  45.                 For i = 0 To A(ii).Rows.Length - 1      '寫入資料
  46.                 'Debug.Print ii  可找出所要資料的 table 範圍
  47.                 k = k + 1
  48.                 For j = 0 To 5
  49.                     Cells(k, j + 1) = A(ii).Rows(i).Cells(j).innerText
  50.                 Next
  51.             Next
  52.             Next
  53.             .Range("C5").Cut Range("D5")
  54.             With .Range("B5:C5,D5:E5")
  55.                 .HorizontalAlignment = xlCenter
  56.                 .VerticalAlignment = xlCenter
  57.                 .Merge
  58.             End With
  59.         End With
  60.         .Quit        '關閉網頁
  61.     End With
  62. End Sub
複製代碼
  1. Option Explicit
  2. Dim 網頁 As Object
  3. Sub Ex簡易手動()
  4.     '程式第一次執行: 打開網頁,在網頁中手動,選擇資料後 , 按[搜尋]鍵!!
  5.     '程式第二次執行: 讀取網頁資料到 Excel中.
  6.     '往後在網頁資料有修改,只需執行一次即可讀取網頁資料到 Excel中.
  7.     Dim i As Integer, ii As Integer, k As Integer, j As Integer, A As Object
  8.     On Error GoTo RE網頁
  9. 1:
  10.     If 網頁 Is Nothing Then
  11.         Set 網頁 = CreateObject("InternetExplorer.Application")
  12.          With 網頁
  13.             .Visible = True
  14.             .Navigate "http://mops.twse.com.tw/mops/web/t164sb04"
  15.             .Height = 500
  16.             .Width = 1300
  17.         End With
  18.         Application.WindowState = xlMinimized  'Excel 最小化
  19.         Exit Sub
  20.     End If
  21.     If 網頁.Visible = False Then
  22.         網頁.Value = True
  23.         Application.WindowState = xlMinimized
  24.         Exit Sub
  25.     End If
  26.     '**********讀取網頁 資料 *******************
  27.     Set A = 網頁.document.getelementsbytagname("table")
  28.     With ActiveSheet                               '作用中的工作表
  29.          .Cells.Clear
  30.          On Error Resume Next
  31.         For ii = 11 To A.Length - 1                     
  32.             For i = 0 To A(ii).Rows.Length - 1      '寫入資料
  33.                 k = k + 1
  34.                 For j = 0 To 5
  35.                     Cells(k, j + 1) = A(ii).Rows(i).Cells(j).innerText
  36.                 Next
  37.             Next
  38.         Next
  39.         .Range("C5").Cut .Range("D5")
  40.         With .Range("B5:C5,D5:E5")
  41.             .HorizontalAlignment = xlCenter
  42.             .VerticalAlignment = xlCenter
  43.             .Merge
  44.         End With
  45.     End With
  46. Exit Sub
  47. RE網頁:   '
  48.      Set 網頁 = Nothing
  49.     Resume 1
  50. End Sub
複製代碼

作者: yuch8663    時間: 2013-5-19 16:46

回復 2# GBKEE


    請問GBKEE大大,如果要一次輸入更多公司代號讓程式自動下載後另存新檔,應該如何修改,謝謝。
作者: randomwalk    時間: 2013-5-19 16:47

回復 2# GBKEE


謝謝GBKEE指導
這個網頁是綜合損益表,2013年後上市櫃公司由公布損益表改為公布綜合損益表,
目前只有第一季公布,所以最新資料跟歷史資料都是第一季,
等第二季公布後,就不同了

再請教:
小弟習慣用以下這種語法在抓網頁,似乎前提是能夠找出資料的http,請問上面的綜合損益表能夠找出嗎?
With ActiveSheet.QueryTables.Add(Connection:="URL;http://dj.mybank.com.tw/z/zc/zca/zca_" & mywb1.Sheets("Price").Cells(i, "A") & ".asp.htm", Destination:=Range("$A$1"))
End With

另外GBKEE兄上面提供的程式中,用到的
.getelementsbytagname("INPUT")    =>"co_id" 為公司代號
.getelementsbytagname("SELECT")   =>有"isnew" "year" "season"
請問要怎樣從網頁知道是("INPUT")  或是("SELECT")  ,以及如何找出他們的name 各是"isnew" "year" "season",

感謝GBKEE兄願意指導,謝謝
作者: GBKEE    時間: 2013-5-19 17:46

回復 3# yuch8663
如果要一次輸入更多公司代號讓程式自動下載後另存新檔
你要如何存檔? 給個範例才知要如何修改.
回復 4# randomwalk
改版最大就是不讓用 QueryTables.Add 大量讀取資料,作流量控管的.

如圖慢慢研究

    [attach]15026[/attach]
作者: lalalada    時間: 2013-5-20 21:38

以2498在102年第一季的資料來說
varbody="encodeURIComponent=1&step=1&firstin=1&off=1&keyword4=&code1=&TYPEK2=&checkbtn=&queryName=co_id&TYPEK=all&isnew=false&co_id=2498&year=102&season=01"
由此可以觀察到對應的參數位置
使用post方法
最後另存成csv
改一下就可以全部下載囉
我的vba正在跑不能測 所以以上皆猜測 不過這些網站的原理幾乎都一樣...
作者: cji3cj6xu6    時間: 2013-5-22 18:46

謝謝版大的問題,也謝謝g大的回覆,剛好我也在想要如何發問。

G大想請教一下,
我將你的表頭改為

For DQ = 1 To 5
    DQQ = 6
    Sheets(DQQ).Select
     co_id = Range("A" & DQ).Value
     Sheets(DQ).Select
    'If Not IsNumeric(Val(co_id)) Or Len(co_id) <> 4 Then Exit Sub              '不是四位數的數字
    isnew = 1

也就是說,我將個股的代號放在page6的a1∼a5,但是想請教一下,
為何只有第一項的資料會進入page1,其他的page2 ~ page5 均為空白,
不曉得您的程式哪裡還需要動到。
Thanks.
作者: GBKEE    時間: 2013-5-22 20:12

回復 7# cji3cj6xu6
請上傳檔案說明一下.
沒看到完整的程式j我也不暸解, 為何只有第一項的資料會進入page1,其他的page2 ~ page5 均為空白
作者: cji3cj6xu6    時間: 2013-5-22 22:17

Dear G大謝謝您的費心,如上所提,我只修改表頭與endsub前的Next DQ,僅此而已,
實際上也看到IE的股票代號有動作,但page2 ~page5 並沒有將資料帶進來??

Sub Ex()
    Dim i As Integer, s As Integer, k As Integer, A, ii, j
    Dim co_id As String, isnew As String, season As String
    Dim DQ as Integer, DQQ As Integer
     For DQ = 1 To 5
    DQQ = 6
    Sheets(DQQ).Select
     co_id = Range("A" & DQ).Value
     Sheets(DQ).Select
    isnew = 1
    With CreateObject("InternetExplorer.Application")
        .Visible = True
        .Navigate "http://mops.twse.com.tw/mops/web/t164sb04"
        Do While .Busy Or .ReadyState <> 4: DoEvents: Loop
        With .document
            For Each A In .getelementsbytagname("INPUT")
                If A.Name = "co_id" Then A.Value = co_id
            Next
            For Each A In .getelementsbytagname("SELECT")
                If A.Name = "isnew" Then
                    A.Value = True
                    If isnew = "2" Then
                        A.Focus
                        Application.Wait Now + #12:00:02 AM#
                        Application.SendKeys "{DOWN}"
                        Application.Wait Now + #12:00:02 AM#
                        Application.SendKeys "{ENTER}"
                    End If
                End If
                If A.Name = "year" And isnew = "2" Then A.Value = Split(season, ",")(0)
                If A.Name = "season" And isnew = "2" Then A.Value = Split(season, ",")(1)
            Next
            For Each A In .getelementsbytagname("INPUT")
                If Trim(A.Value) = "搜尋" And A.Name <> "rulesubmit" Then A.Click        '按下[搜索]鍵
            Next
        End With
        Application.Wait Now + #12:00:10 AM#                     '等待網頁下載資料
        Set A = .document.getelementsbytagname("table")
        On Error Resume Next       '***有些table沒Rows資料會產生錯誤 不理會它,程式繼續走
        With ActiveSheet
            .Cells.Clear
           '************************
           ' For ii = 0 To A.Length - 1        '不知道table範圍在何處: 從0開始
           '******************************
            For ii = 11 To A.Length - 1        ''從11開始 用 Debug.Print ii  找出所要資料的table範圍
                For i = 0 To A(ii).Rows.Length - 1      '寫入資料
                'Debug.Print ii  可找出所要資料的 table 範圍
                k = k + 1
                For j = 0 To 5
                    Cells(k, j + 1) = A(ii).Rows(i).Cells(j).innerText
                Next
            Next
            Next
            .Range("C5").Cut Range("D5")
            With .Range("B5:C5,D5:E5")
                .HorizontalAlignment = xlCenter
                .VerticalAlignment = xlCenter
                .Merge
            End With
        End With
        .Quit        '關閉網頁
    End With
Next DQ
End Sub
作者: cji3cj6xu6    時間: 2013-5-22 23:13

Dear G大,

我找到問題了。
謝謝您送的這個武器,好用。
因為K值會遞增所影響,所以多加一行K=0即可。

For DQ = 1 To 5
    DQQ = 6
    Sheets(DQQ).Select
     co_id = Range("A" & DQ).Value
    Sheets(DQ).Select
    isnew = 1
    k = 0
    ...........
   Next DQ
作者: GBKEE    時間: 2013-5-23 07:24

回復 10# cji3cj6xu6
修改一下 IE不必開開關關
  1. Option Explicit
  2. Sub Ex()
  3.     Dim i As Integer, s As Integer, k As Integer, A, ii, j
  4.     Dim co_id As String, isnew As String, season As String
  5.     Dim DQ As Integer, DQQ As Integer
  6.     With CreateObject("InternetExplorer.Application")
  7.         .Visible = True
  8.         .Navigate "http://mops.twse.com.tw/mops/web/t164sb04"
  9.         Do While .Busy Or .ReadyState <> 4: DoEvents: Loop
  10.         DQQ = 6
  11.         For DQ = 1 To 5
  12.             co_id = Sheets(DQQ).Range("A" & DQ).Value
  13.             'Sheets(DQ).Select                  '不必一動工作表
  14.             isnew = 1
  15.             With .document
  16.                 For Each A In .getelementsbytagname("INPUT")
  17.                     If A.Name = "co_id" Then A.Value = co_id
  18.                 Next
  19.                 For Each A In .getelementsbytagname("SELECT")
  20.                     If A.Name = "isnew" Then
  21.                         A.Value = True
  22.                         If isnew = "2" Then
  23.                             A.Focus
  24.                             Application.Wait Now + #12:00:02 AM#
  25.                             Application.SendKeys "{DOWN}"
  26.                             Application.Wait Now + #12:00:02 AM#
  27.                             Application.SendKeys "{ENTER}"
  28.                         End If
  29.                     End If
  30.                     If A.Name = "year" And isnew = "2" Then A.Value = Split(season, ",")(0)
  31.                     If A.Name = "season" And isnew = "2" Then A.Value = Split(season, ",")(1)
  32.                 Next
  33.                 For Each A In .getelementsbytagname("INPUT")
  34.                     If Trim(A.Value) = "搜尋" And A.Name <> "rulesubmit" Then A.Click        '按下[搜索]鍵
  35.                 Next
  36.             End With
  37.             Application.Wait Now + #12:00:10 AM#                     '等待網頁下載資料
  38.             Set A = .document.getelementsbytagname("table")
  39.             On Error Resume Next       '***有些table沒Rows資料會產生錯誤 不理會它,程式繼續走
  40.             With Sheets(DQ)            '*** 物件 : 指定工作表  ****
  41.                 .Cells.Clear
  42.            '************************
  43.            ' For ii = 0 To A.Length - 1        '不知道table範圍在何處: 從0開始
  44.            '******************************
  45.                 .[A1] = co_id
  46.                 k = 1
  47.                 For ii = 11 To A.Length - 1        ''從11開始 用 Debug.Print ii  找出所要資料的table範圍
  48.                     For i = 2 To A(ii).Rows.Length - 1      '寫入資料
  49.                         'Debug.Print ii  可找出所要資料的 table 範圍
  50.                         k = k + 1
  51.                         For j = 0 To 5
  52.                             .Cells(k, j + 1) = A(ii).Rows(i).Cells(j).innerText
  53.                         Next
  54.                     Next
  55.                 Next
  56.                 .Range("C2").Cut .Range("D2")
  57.             With .Range("B2:C2,D2:E2")
  58.           '  .Select
  59.                 .HorizontalAlignment = xlCenter
  60.                 .VerticalAlignment = xlCenter
  61.                 .Merge
  62.             End With
  63.             End With
  64.         Next DQ
  65.         .Quit        '關閉網頁
  66.     End With
  67. End Sub
複製代碼

作者: cji3cj6xu6    時間: 2013-5-23 08:59

謝謝g大∼∼
作者: cji3cj6xu6    時間: 2013-5-23 18:50

想再請教一下,
若是a20 的儲存格為中文字"如果",
假設我要判斷a1~a50 的儲存格是否有此一中文字"如果",
當條件發生時,則我的某個數值為B20,否則為c20的儲存格裡的數值。
請問要如何判斷?

謝謝∼
作者: stillfish00    時間: 2013-5-23 20:03

你的B20 , C20都是固定位置嗎?
若是
x = IIf(InStr(Join(Application.Transpose([A1:A50].Value), ""), "如果") > 0, [B20], [C20])
若不是固定位置而是相對於 "如果" 儲存格
問題又怪怪的,沒找到 "如果" 儲存格,哪來的C20
作者: cji3cj6xu6    時間: 2013-5-23 22:49

謝謝stillfish00大的回覆,

您說的沒錯,我寫的不夠清楚。
想再請教一下,
若是在A1 ~ A50裡,A20 的儲存格為"如果",則c55的值為B20,
但若是A21 的儲存格才為"如果",則C55的值為B21
也就是說"如果"不確定是存放在A1 ~A50的哪個地方,
而C55的值也跟著變動,不曉得這樣要如何修改?

繼續思考中~

謝謝!
作者: stillfish00    時間: 2013-5-24 01:36

回復 15# cji3cj6xu6
  1. Sub TEST()
  2.     Dim f
  3.     With ActiveSheet
  4.         Set f = .[A1:A50].Find(What:="如果", LookIn:=xlValues, LookAt:=xlPart)
  5.         .[C55] = IIf(f Is Nothing, "找不到", f.Offset(, 1).Value)
  6.     End With
  7. End Sub
複製代碼

作者: stillfish00    時間: 2013-5-24 02:09

回復 15# cji3cj6xu6
更正一下(因為IIF正反都會先運算會有問題)
  1. Sub TEST()
  2.     Dim f
  3.     With ActiveSheet
  4.         Set f = .[A1:A50].Find(What:="如果", LookIn:=xlValues, LookAt:=xlPart)
  5.         If f Is Nothing Then
  6.             .[C55] = "找不到"
  7.         Else
  8.             .[C55] = f.Offset(, 1).Value
  9.         End If
  10.     End With
  11. End Sub
複製代碼

作者: cji3cj6xu6    時間: 2013-5-24 09:05

謝謝stillfish00大的回覆,

這次又可以多學個指令了。
對於vba不熟,只能用些簡單的指令,看來要多學一點了。
通常我只會硬刻一套可用的vba,
比如,這次要是沒有人回覆,我就會用錄製新巨集的方式,
錄下取代"如果"的方法,然後以數字比對的方式來設定C55。

謝謝stillfish00∼
作者: itservice04    時間: 2013-8-23 10:05

對原作者 至上最高的感寫
我引用原本的code小做修改如下

Sub Ex()
    Dim i As Integer, s As Integer, k As Integer, A, ii, j
    Dim co_id As String, isnew As String, season As String
    Dim input_year As String
    co_id = InputBox("請輸入 公司代號")
    If Not IsNumeric(Val(co_id)) Or Len(co_id) <> 4 Then Exit Sub              '不是四位數的數字
      isnew = "2"
  
    With CreateObject("InternetExplorer.Application")
        .Visible = True
        .Navigate "http://mops.twse.com.tw/mops/web/query6_1"
        Do While .Busy Or .ReadyState <> 4: DoEvents: Loop
        With .document
            For Each A In .getelementsbytagname("INPUT")
                If A.Name = "co_id" Then A.Value = co_id
            Next
            For Each A In .getelementsbytagname("SELECT")
                If A.Name = "isnew" Then
                    A.Value = True
                    If isnew = "2" Then
                        A.Focus
                        Application.Wait Now + #12:00:02 AM#
                        Application.SendKeys "{DOWN}"
                        Application.Wait Now + #12:00:02 AM#
                        Application.SendKeys "{ENTER}"
                    End If
                End If
              If A.Name = "year" And isnew = "2" Then A.Value = "101"
              If A.Name = "month" And isnew = "2" Then A.Value = "05"
  
            Next
            For Each A In .getelementsbytagname("INPUT")
                If Trim(A.Value) = "搜尋" And A.Name <> "rulesubmit" Then A.Click        '按下[搜索]鍵
            Next
        End With
        Application.Wait Now + #12:00:10 AM#                     '等待網頁下載資料
        Set A = .document.getelementsbytagname("table")
        On Error Resume Next       '***有些table沒Rows資料會產生錯誤 不理會它,程式繼續走
        With ActiveSheet
            .Cells.Clear
           '************************
           ' For ii = 0 To A.Length - 1        '不知道table範圍在何處: 從0開始
           '******************************
            For ii = 11 To A.Length - 1        ''從11開始 用 Debug.Print ii  找出所要資料的table範圍
                For i = 0 To A(ii).Rows.Length - 1      '寫入資料
                'Debug.Print ii  可找出所要資料的 table 範圍
                k = k + 1
                For j = 0 To 5
                    Cells(k, j + 1) = A(ii).Rows(i).Cells(j).innerText
                Next
            Next
            Next
            .Range("C5").Cut Range("D5")
            With .Range("B5:C5,D5:E5")
                .HorizontalAlignment = xlCenter
                .VerticalAlignment = xlCenter
                .Merge
            End With
        End With
        '.Quit        '關閉網頁
    End With
End Sub



我遇到了IE cookie的問題,"年份" 並不會跟著程式碼中定義的"101" 而變更到101
只有紀錄手動差詢過的年份值而作動,例如
C:\Users\user\AppData\Local\Microsoft\Windows\Temporary Internet Files\Cookie:[email protected]/
內容如下
"D102%"
如果我改成D101% ,在查詢時就可以變成101年,請問VBA有沒有解決方式
我曾經是過用VBA 輸出檔案到這資料夾好像沒有辦法
這個是我測試的程式碼:
Sub XlsToTxT()
Dim MYstr As String, i As Integer                '定義屬性
Open "C:\Users\user\AppData\Local\Microsoft\Windows\Temporary Internet Files\63MX5O7N.txt" For Output As #1     '定義Output File位置
Open "C:\63MX5O7N.txt" For Output As #1     '定義Output File位置
    For i = 1 To 10                                    '由 Row 1to10
        MYstr = Cells(i, 1)                            '輸出的內容 (或你要的東西,可在此開始自己定義吧~)
        Print #1, MYstr
    Next i
Close #1
End Sub

newmops2
co_id%3D5489%7Cyear%3D102%7Cmonth%3D05%7C
mops.twse.com.tw/
1088
3112764800
30318700
2461393296
30318499
*

經過輸出動作後並不會回存為cookie檔案
會真的存成一個TXT檔
作者: heavenweaver    時間: 2014-3-16 02:33

回復 6# lalalada
我也試了一下,發覺用像您同樣的方法先找出參數再QueryTables到Xls的工作表上,比較適合我目前的想法,我習慣以AutoIT自動開啟EXCEL並另存CSV。
[attach]17773[/attach]




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