【问题标题】:Download files from a web page using VBA HTML使用 VBA HTML 从网页下载文件
【发布时间】:2013-06-17 23:24:34
【问题描述】:

几个月来,我一直在拼命尝试自动化一个过程,即下载、管理和保存一个给定位置的 csv 文件。 到目前为止,我只使用 excel vba 管理打开网页并单击底部下载 csv 文件,但代码停止并需要手动干预才能完成,如果可能的话,我希望它能够完全自动化。 查看使用的代码(我不是作者):

Sub WebDataExtraction()
Dim URL As String
Dim IeApp As Object
Dim IeDoc As Object
Dim ieForm As Object
Dim ieObj As Object
Dim objColl As Collection

URL = "http://www.bmreports.com/bsp/BMRSSystemData.php?pT=DDAD&zT=N&dT=NRT"

Set IeApp = CreateObject("InternetExplorer.Application")
IeApp.Visible = True
IeApp.Navigate URL

Do Until IeApp.ReadyState = READYSTATE_COMPLETE
Loop

Set IeDoc = IeApp.Document
For Each ele In IeApp.Document.getElementsByTagName("span")

If ele.innerHTML = "CSV" Then
Application.Wait (Now + TimeValue("0:00:15"))
DoEvents
ele.Click
'At this point you need to Save the document manually
' or figure out for yourself how to automate this interaction.
Test_Save_As_Set_Filename
File_Download_Click_Save
End If

Next

IeApp.Quit
End Sub"

提前致谢

农齐奥

【问题讨论】:

  • 使用XMLHTTP 比自动化 IE 更容易。例如,stackoverflow.com/questions/7747877/…
  • 感谢您的建议,但我对 XMLHTTP 一点也不熟悉
  • 顺便说一句,这看起来像我的代码。我记得我写过评论“自己弄清楚如何自动化这种交互”。
  • @DavidZemens 这是你的代码,事实上我指定我不是它的作者,我留下了你所有的评论我不想把你的代码归功于;)谢谢你
  • 哦,我不是那个意思。欢迎您使用我的代码,我只是觉得再次看到我的代码很有趣:) 干杯。

标签: html excel vba


【解决方案1】:

我发布了第二个答案,因为我相信我的第一个答案对于许多类似的应用程序来说已经足够了,所以它在这种情况下不起作用。

其他方法失败的原因:

  • .Click 方法:这会引发一个新窗口,该窗口需要用户在运行时输入,似乎无法使用WinAPI 来控制此窗口。或者,至少不是我能确定的任何方式。代码执行在.Click 行停止,直到用户手动干预,无法使用GoToWait 或任何其他方法来规避此行为。
  • 使用WinAPI函数直接下载源文件不起作用,因为按钮的URL不包含文件,而是动态提供文件的js函数。

这是我提出的解决方法:

您可以读取网页的.body.InnerText,使用FileSystemObject 将其写入纯文本/csv 文件,然后结合Regular Expressions 和字符串操作,将数据解析为正确分隔的CSV 文件。

Sub WebDataExtraction()
    Dim url As String
    Dim fName As String
    Dim lnText As String
    Dim varLine() As Variant
    Dim vLn As Variant
    Dim newText As String
    Dim leftText As String
    Dim breakTime As Date
'## Requires reference to Microsoft VBScript Regular Expressions 5.5
    Dim REMatches As MatchCollection
    Dim m As Match
'## Requires reference to Microsoft Internet Controls
    Dim IeApp As InternetExplorer
'## Requires reference to Microsoft HTML object library
    Dim IeDoc As HTMLDocument
    Dim ele As HTMLFormElement
'## Requires reference to Microsoft Scripting Runtime
    Dim fso As FileSystemObject
    Dim f As TextStream
    Dim ln As Long: ln = 1


    breakTime = DateAdd("s", 60, Now)
    url = "http://www.bmreports.com/bsp/BMRSSystemData.php?pT=DDAD&zT=N&dT=NRT"
    Set IeApp = CreateObject("InternetExplorer.Application")

    With IeApp
        .Visible = True
        .Navigate url

        Do Until .ReadyState = 4
        Loop

        Set IeDoc = .Document
    End With
    'Wait for the data to display on the page
    Do
        If Now >= breakTime Then
            If MsgBox("The website is taking longer than usual, would you like to continue waiting?", vbYesNo) = vbNo Then
                GoTo EarlyExit
            Else:
                breakTime = DateAdd("s", 60, Now)
            End If
        End If
    Loop While Trim(IeDoc.body.innerText) = "XML CSV Please Wait Data Loading Sorting"

    '## Create the text file
    fName = ActiveWorkbook.Path & "\exported-csv.csv"
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set f = fso.OpenTextFile(fName, 2, True, -1)
    f.Write IeDoc.body.innerText
    f.Close
    Set f = Nothing

    '## Read the text file
    Set f = fso.OpenTextFile(fName, 1, False, -1)
    Do
        lnText = f.ReadLine
        '## The data starts on the 4th line in the InnerText.
        If ln >= 4 Then
            '## Return a collection of matching date/timestamps to which we can parse
            Set REMatches = SplitLine(lnText)
            newText = lnText
            For Each m In REMatches
                newText = Replace(newText, m.Value, ("," & m.Value & ","), , -1, vbTextCompare)
            Next
            '## Get rid of consecutive delimiters:
            Do
                newText = Replace(newText, ",,", ",")
            Loop While InStr(1, newText, ",,", vbBinaryCompare) <> 0
            '## Then use some string manipulation to parse out the first 2 columns which are
            '   not a match to the RegExp we used above.
            leftText = Left(newText, InStr(1, newText, ",", vbTextCompare) - 1)
            leftText = Left(leftText, 10) & "," & Right(leftText, Len(leftText) - 10)
            newText = Right(newText, Len(newText) - InStr(1, newText, ",", vbTextCompare))
            newText = leftText & "," & newText

            '## Store these lines in an array
            ReDim Preserve varLine(ln - 4)
            varLine(ln - 4) = newText
        End If
        ln = ln + 1

    Loop While Not f.AtEndOfStream
    f.Close

'## Re-open the file for writing the delimited lines:
    Set f = fso.OpenTextFile(fName, 2, True, -1)
    '## Iterate over the array and write the data in CSV:
    For Each vLn In varLine
        'Omit blank lines, if any.
        If Len(vLn) <> 0 Then f.WriteLine vLn
    Next
    f.Close

EarlyExit:
    Set fso = Nothing
    Set f = Nothing
    IeApp.Quit
    Set IeApp = Nothing

End Sub

Function SplitLine(strLine As String) As MatchCollection
'returns a RegExp MatchCollection of Date/Timestamps found in each line
'## Requires reference to Microsoft VBScript Regular Expressions 5.5
Dim RE As RegExp
Dim matches As MatchCollection
    Set RE = CreateObject("vbscript.regexp")
    With RE
        .MultiLine = False
        .Global = True
        .IgnoreCase = True
        '## Use this RegEx pattern to parse the date & timestamps:
        .Pattern = "(19|20)\d\d[-](0[1-9]|1[012])[-](0[1-9]|[12][0-9]|3[01])[ ]\d\d?:\d\d:\d\d"
    End With
    Set matches = RE.Execute(strLine)
    Set SplitLine = matches
End Function

【讨论】:

  • 再次感谢您的合作,但代码在这里中断:Set REmatches = SplitLine(lnText) "sub or function not defined" 我尝试使用 split 但仍然收到错误再次感谢
  • 哦,我忘了包含函数SplitLine 的代码 :) 我马上更新!
  • 代码中断为:"leftText = Left(newText, Application.WorksheetFunction.Find(",", newText, 1) - 1)" 这似乎在 VBA 中不受支持,我尝试使用instr 相当于 vba 中的 find 但我仍然收到错误消息:“leftText = Left(newText, InStr(1, newText, ",", vbTextCompare) - 1)"
  • VBA 绝对支持Application.WorksheetFunction.Find。为了将来参考,如果您收到“错误”,请务必花时间告诉我什么错误消息。我读不懂你的心思。如果您能告诉我出现此错误时newText 的值是多少,这也会很有帮助。
  • 而且,为了指出另一个明显的问题:出于礼貌,如果您花 1 秒钟时间至少对我的所有帮助表示赞同,那就太好了到目前为止,我已经给你了。你已经编写了你正在使用的代码的 0%。我免费做这个。所以,请考虑为我迄今为止给你的答案投票。
【解决方案2】:

编辑

我使用 URL 测试了我的原始答案代码:

http://www.bmreports.com/bsp/BMRSSystemData.php?pT=DDAD&amp;zT=N&amp;dT=NRT#saveasCSV

但是对于这个站点,这种方法似乎不起作用。 ele.Click 似乎没有启动下载,它只是打开网页上的数据表格。要下载,您需要右键单击/另存为。如果您已经做到了这一点(我怀疑,基于您正在调用的子例程,但您没有提供代码),那么您可能可以使用 Win API 来获取“保存”对话框的 HWND 并可能自动执行该操作事件。 Santosh 提供了一些相关信息:

VBA - Go to website and download file from save prompt

这里也是一个很好的资源,可以帮助您解决问题:

http://social.msdn.microsoft.com/Forums/en-US/beb6fa0e-fbc8-49df-9f2e-30f85d941fad/download-file-from-ie-with-vba

原答案

如果您能够确定 CSV 的 URL,则可以使用此子例程打开与 CSV 数据的连接并将其直接导入工作簿。您可能需要对导入的数据自动执行文本到列的操作,但可以使用宏记录器轻松复制。我在下面的Test() 子例程中放了一个例子。

您可以轻松地对其进行修改以在新工作簿中添加 QueryTables,然后在该工作簿上自动执行 SaveAs 方法以将文件保存为 CSV。

此示例使用雅虎财经、福特汽车公司的已知 URL,并将在活动工作表的单元格 A1 中添加带有 CSV 数据的 QueryTables。这可以很容易地修改以将其放入另一个工作表、另一个工作簿等中。

Sub Test()
Dim MyURL as String
MyURL = "http://ichart.finance.yahoo.com/table.csv?s=GM&a0&b=1&c2010&d=05&e=20&f=2013&g=d&ignore=.csv"

OpenURL MyURL

'Explode the CSV data:
Range("A:A").TextToColumns Destination:=Range("A1"), DataType:=xlDelimited, _
    TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=False, _
    Semicolon:=False, Comma:=True, Space:=False, Other:=False, FieldInfo _
    :=Array(Array(1, 3), Array(2, 1), Array(3, 1), Array(4, 1), Array(5, 1), Array(6, 1), _
    Array(7, 1)), TrailingMinusNumbers:=True

End Sub

Private Sub OpenURL(fullURL As String)

'This opens the CSV in querytables connection.
On Error GoTo ErrOpenURL
    With ActiveSheet.QueryTables.Add(Connection:= _
        "URL;" & fullURL, Destination:=Range("A1"))
        .Name = fullURL
        .FieldNames = True
        .RowNumbers = False
        .FillAdjacentFormulas = False
        .PreserveFormatting = True
        .RefreshOnFileOpen = False
        .BackgroundQuery = True
        .RefreshStyle = xlInsertDeleteCells
        .SavePassword = True
        .SaveData = True
        .AdjustColumnWidth = True
        .RefreshPeriod = 0
        .WebSelectionType = xlEntirePage
        .WebFormatting = xlWebFormattingAll
        .WebPreFormattedTextToColumns = True
        .WebConsecutiveDelimitersAsOne = True
        .WebSingleBlockTextImport = False
        .WebDisableDateRecognition = False
        .WebDisableRedirections = False
        .Refresh BackgroundQuery:=False
    End With

ExitOpenURL:
Exit Sub 'if all goes well, you can exit

'Error handling...

ErrOpenURL:
Err.Clear
bCancel = True
Resume ExitOpenURL


End Sub

【讨论】:

  • Querytable 不适用于该网站,我已经尝试过但没有任何好的结果。无论如何,谢谢。
  • @NunzioPuntillo 我很清楚这一点,这就是为什么我解释它为什么不起作用,并为您提供一些额外的信息。我怀疑您正在寻找的答案在其中一个或两个链接中。跟随他们,尝试这些方法,看看他们是否能解决你的问题。您或许可以通过这种方式回答您自己的问题。
  • @DevidZemens 我试过了,但它不起作用:(
  • 我看到SaveAs 对话框正在干扰运行时。让我想想……
  • 这很棘手......我认为从页面源解析表格可能更容易,但它不在页面源中(表格和下载来自未公开的javascript函数在源中)。我认为this (kind of simulate a right-click "save target as") 可能会有所帮助,但它不适用于像这样从 JS 提供的文件。
猜你喜欢
  • 1970-01-01
  • 2017-01-30
  • 2015-12-07
  • 1970-01-01
  • 1970-01-01
  • 2019-01-15
  • 1970-01-01
  • 1970-01-01
  • 2017-04-09
相关资源
最近更新 更多