VBA IE自动化-等待下载完成

VBA IE自动化-等待下载完成,vba,internet-explorer,download,browser-automation,ie-automation,Vba,Internet Explorer,Download,Browser Automation,Ie Automation,我正在尝试通过Internet explorer自动完成一些任务,包括下载文件,然后将其复制到其他目录并重命名。 我或多或少成功地找到了有关如何执行此操作的信息,代码正在运行,但有例外,因此如果有人能帮助我改进此代码,我将不胜感激 我想做两件事: 插入一个循环,这样脚本将等待某些元素出现,然后才能继续执行。我已经在页面上找到了一些东西,但是,我也希望像这里建议的那样,构建一个最长的等待时间 当代码正在下载文件时,它还应该等待下载完成,然后再继续。目前我正在使用“wait”命令,但下载时间可能会有

我正在尝试通过Internet explorer自动完成一些任务,包括下载文件,然后将其复制到其他目录并重命名。 我或多或少成功地找到了有关如何执行此操作的信息,代码正在运行,但有例外,因此如果有人能帮助我改进此代码,我将不胜感激

我想做两件事:

  • 插入一个循环,这样脚本将等待某些元素出现,然后才能继续执行。我已经在页面上找到了一些东西,但是,我也希望像这里建议的那样,构建一个最长的等待时间
  • 当代码正在下载文件时,它还应该等待下载完成,然后再继续。目前我正在使用“wait”命令,但下载时间可能会有所不同,在这种情况下脚本将停止。我还找到了一个解决方案,等待“打开文件夹”按钮出现,但我不知道如何在代码中实现它。以下是我找到的代码:
  • 另外,可能还有另一种解决方案,不是将文件保存在默认下载位置,而是执行“另存为”,然后以这种方式定义目录和文件名

    提前谢谢你

    下面是我正在使用的源代码。作为一个例子,我正在使用MicrosoftPage下载示例文件

        Option Explicit
    #If VBA7 Then
        Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr)
    
        Private Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
      (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, _
      ByVal lpsz2 As String) As LongPtr
    
    #Else
        Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
    
        Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
    (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, _
    ByVal lpsz2 As String) As Long
    #End If
    
    Sub MyIEauto()
    
        Dim ieApp As InternetExplorer
        Dim ieDoc As Object
    
        Set ieApp = New InternetExplorer
    
        ieApp.Visible = True
        ieApp.navigate "https://docs.microsoft.com/en-us/power-bi/sample-financial-download"
        Do While ieApp.Busy: DoEvents: Loop
        Do Until ieApp.readyState = READYSTATE_COMPLETE: DoEvents: Loop
    
        ieApp.navigate "http://go.microsoft.com/fwlink/?LinkID=521962"
        Do While ieApp.Busy: DoEvents: Loop
        Do Until ieApp.readyState = READYSTATE_COMPLETE: DoEvents: Loop
    
        Dim AutomationObj As IUIAutomation
        Dim WindowElement As IUIAutomationElement
        Dim Button As IUIAutomationElement
        Dim hWnd As LongPtr
    
        Set AutomationObj = New CUIAutomation
    
        Do While ieApp.Busy Or ieApp.readyState <> 4: DoEvents: Loop
        Application.Wait (Now + TimeValue("0:00:05"))
        hWnd = ieApp.hWnd
        hWnd = FindWindowEx(hWnd, 0, "Frame Notification Bar", vbNullString)
        If hWnd = 0 Then Exit Sub
    
        Set WindowElement = AutomationObj.ElementFromHandle(ByVal hWnd)
        Dim iCnd As IUIAutomationCondition
        Set iCnd = AutomationObj.CreatePropertyCondition(UIA_NamePropertyId, "Save")
    
        Set Button = WindowElement.FindFirst(TreeScope_Subtree, iCnd)
        Dim InvokePattern As IUIAutomationInvokePattern
        Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
        InvokePattern.Invoke
        Application.Wait (Now + TimeValue("0:00:05"))
    
        FileCopy "C:\Users\Name\Downloads\Financial Sample.xlsx", "C:\Users\Name\Desktop\Financial Sample.xlsx"
        Name "C:\Users\Name\Desktop\Financial Sample.xlsx" As "C:\Users\Name\Desktop\Hello.xlsx"
        Application.Wait (Now + TimeValue("0:00:01"))
    
        Dim KillFile As String
        KillFile = "C:\Users\Name\Downloads\Financial Sample.xlsx"
        If Len(Dir$(KillFile)) > 0 Then
        SetAttr KillFile, vbNormal
         Kill KillFile
    End If
    
    End Sub
    
    选项显式
    #如果是VBA7,则
    声明PtrSafe子睡眠库“kernel32”(ByVal dwr作为LongPtr)
    私有声明PtrSafe函数FindWindowEx Lib“user32”别名“FindWindowExA”_
    (ByVal hWnd1作为LongPtr,ByVal hWnd2作为LongPtr,ByVal lpsz1作为字符串_
    ByVal lpsz2作为字符串)作为LongPtr
    #否则
    公共声明子睡眠库“kernel32”(ByVal的长度为毫秒)
    私有声明函数FindWindowEx Lib“user32”别名“FindWindowExA”_
    (ByVal hWnd1为长,ByVal hWnd2为长,ByVal lpsz1为字符串_
    ByVal lpsz2(作为字符串)一样长
    #如果结束
    次MyIEauto()
    Dim ieApp作为InternetExplorer
    Dim ieDoc作为对象
    设置ieApp=新的InternetExplorer
    ieApp.Visible=True
    ieApp.navigate“https://docs.microsoft.com/en-us/power-bi/sample-financial-download"
    在ieApp.Busy:DoEvents:Loop时执行
    直到ieApp.readyState=readyState\u完成:DoEvents:Loop
    ieApp.navigate“http://go.microsoft.com/fwlink/?LinkID=521962"
    在ieApp.Busy:DoEvents:Loop时执行
    直到ieApp.readyState=readyState\u完成:DoEvents:Loop
    Dim Automation作为iUI自动化
    将WindowElement调暗为IUIAutomationeElement
    调暗按钮作为IUIAutomationeElement
    变暗hWnd为长PTR
    Set AutomationObj=新CUI自动化
    当ieApp.Busy或ieApp.readyState 4:DoEvents:Loop时执行
    Application.Wait(现在+时间值(“0:00:05”))
    hWnd=ieApp.hWnd
    hWnd=FindWindowEx(hWnd,0,“帧通知栏”,vbNullString)
    如果hWnd=0,则退出Sub
    设置WindowElement=AutomationObj.ElementFromHandle(ByVal hWnd)
    Dim iCnd作为IUIAutomation条件
    设置iCnd=AutomationObj.CreatePropertyCondition(UIA_NamePropertyId,“保存”)
    Set Button=WindowElement.FindFirst(TreeScope\u子树,iCnd)
    Dim InvokePattern作为IUIAutomationInvokePattern
    设置InvokePattern=Button.GetCurrentPattern(UIA_InvokePatternId)
    InvokePattern.Invoke
    Application.Wait(现在+时间值(“0:00:05”))
    文件副本“C:\Users\Name\Downloads\Financial Sample.xlsx”,“C:\Users\Name\Desktop\Financial Sample.xlsx”
    将“C:\Users\Name\Desktop\Financial Sample.xlsx”命名为“C:\Users\Name\Desktop\Hello.xlsx”
    Application.Wait(现在+时间值(“0:00:01”))
    将文件设置为字符串
    KillFile=“C:\Users\Name\Downloads\Financial Sample.xlsx”
    如果Len(Dir$(KillFile))>0,则
    SetAttr KillFile,vbNormal
    杀死杀手档案
    如果结束
    端接头
    
    您可以使用函数或FSO
    GetFile
    File.Size
    ,并运行一个循环,等待
    1或2秒,直到文件大小停止更改?这意味着下载已经完成

    {EDIT}下面是一个使用后期绑定的FileSystemObject获取文件大小的函数:


    如果目标是从网站下载文件(如
    Financial Sample.xlsx
    from
    https://docs.microsoft.com/en-us/power-bi/sample-financial-download
    -而且页面实际上不需要显示-还有另一种方法,您可能会发现问题较少

    正如您可能已经发现的那样,以编程方式等待页面加载、单击按钮等可能会成为一个令人头痛的问题。这会增加不可预见/不可预测的因素,如网络延迟、源更改等

    以下方法应适用于任何文件URL(和任何文件类型),即使页面不包含实际链接(如许多视频共享网站)

    以您的示例为例,我们可以像这样使用它:

    downloadFile "http://go.microsoft.com/fwlink/?LinkID=521962", _
        "C:\Users\Name\Desktop\Financial Sample.xlsx"
    
    文件将保存到指定的目标


    可能的安全警告(并防止) 使用此方法,您可能会弹出一个安全警告窗口(取决于您的设置和Windows版本)

    这可以通过多种方式轻松解决:(#3或#4是我的首选)

  • 手动单击“是”

  • 通过编程方式“查找”类似于代码示例的窗口,单击“是”

  • 在Windows Internet选项中启用选项“
    跨域访问数据源”

    • 按Windows键,键入“Internet选项”,然后按Enter键

    • 单击
      安全性
      选项卡

    • Internet
      下,单击
      自定义级别…

    • 在“杂项”下,选择“跨域访问数据源”

  • 使用文件的直接URL而不是间接链接(如Microsoft)
    Sub downloadFile(url As String, filePath As String)
    'Download file located at [url]; save to path/filename [filePath]
    
        Dim WinHttpReq As Object, attempts As Integer, oStream
        attempts = 3 'in case of error, try up to 3 times
        On Error GoTo TryAgain
    TryAgain:
        attempts = attempts - 1
        Err.Clear
        If attempts > 0 Then
            Set WinHttpReq = CreateObject("Microsoft.XMLHTTP")
            WinHttpReq.Open "GET", url, False
            WinHttpReq.send
    
            If WinHttpReq.Status = 200 Then
                Set oStream = CreateObject("ADODB.Stream")
                oStream.Open
                oStream.Type = 1
                oStream.Write WinHttpReq.responseBody
                oStream.SaveToFile filePath, 1 ' 1 = no overwrite, 2 = overwrite
                oStream.Close
                Debug.Print "Saved [" & url & "] to [" & filePath & "]"
            End If
        Else
            Debug.Print "Error downloading [" & url & "]"
        End If
    
    End Sub
    
    downloadFile "http://go.microsoft.com/fwlink/?LinkID=521962", _
        "C:\Users\Name\Desktop\Financial Sample.xlsx"
    
    downloadFile "http://download.microsoft.com/download/1/4/E/14EDED28-6C58-4055-A65C-23B4DA81C4DE/Financial%20Sample.xlsx", _
        "C:\Users\Name\Desktop\Financial Sample.xlsx"
    
      Option Explicit
    #If VBA7 Then
    Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr)
    
    Private Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
    
    
     (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, _
      ByVal lpsz2 As String) As LongPtr
    
    #Else
    Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
    
    Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
    (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, _
    ByVal lpsz2 As String) As Long
    #End If
    
    Sub MyIEauto()
    
    Dim ieApp As InternetExplorer
    Dim ieDoc As Object
    Const DebugMode As Boolean = False
    
    Set ieApp = New InternetExplorer
    
    ieApp.Visible = True
    ieApp.navigate "https://docs.microsoft.com/en-us/power-bi/sample-financial-download"
    Do While ieApp.Busy: DoEvents: Loop
    Do Until ieApp.readyState = READYSTATE_COMPLETE: DoEvents: Loop
    
    ieApp.navigate "http://go.microsoft.com/fwlink/?LinkID=521962"
    Do While ieApp.Busy: DoEvents: Loop
    Do Until ieApp.readyState = READYSTATE_COMPLETE: DoEvents: Loop
    
    Dim AutomationObj As IUIAutomation
    Dim WindowElement As IUIAutomationElement
    Dim Button As IUIAutomationElement
    Dim hWnd As LongPtr
    
    Set AutomationObj = New CUIAutomation
    
    Do While ieApp.Busy Or ieApp.readyState <> 4: DoEvents: Loop
    Application.Wait (Now + TimeValue("0:00:05"))
    hWnd = ieApp.hWnd
    hWnd = FindWindowEx(hWnd, 0, "Frame Notification Bar", vbNullString)
    If hWnd = 0 Then Exit Sub
    
    Set WindowElement = AutomationObj.ElementFromHandle(ByVal hWnd)
    Dim iCnd As IUIAutomationCondition
    Set iCnd = AutomationObj.CreatePropertyCondition(UIA_NamePropertyId, "Save")
    
    Set Button = WindowElement.FindFirst(TreeScope_Subtree, iCnd)
    Dim InvokePattern As IUIAutomationInvokePattern
    Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
    InvokePattern.Invoke
    
    Do
    Set iCnd = AutomationObj.CreatePropertyCondition(UIA_NamePropertyId, "Open folder")
    Set Button = WindowElement.FindFirst(TreeScope_Subtree, iCnd)
        Sleep 200
        If DebugMode Then Debug.Print Format(Now, "hh:mm:ss"); "Open folder"
        DoEvents
    Loop While Button Is Nothing
    
    
      FileCopy "C:\Users\" & Environ("UserName") & "\Downloads\Financial Sample.xlsx", "C:\Users\" & Environ("UserName") & "\Desktop\Financial Sample.xlsx"
    Name "C:\Users\" & Environ("UserName") & "\Desktop\Financial Sample.xlsx" As "C:\Users\" & Environ("UserName") & "\Desktop\Hello.xlsx"
    Application.Wait (Now + TimeValue("0:00:01"))
    
    Dim KillFile As String
    KillFile = "C:\Users\" & Environ("UserName") & "\Downloads\Financial Sample.xlsx"
    If Len(Dir$(KillFile)) > 0 Then
    SetAttr KillFile, vbNormal
     Kill KillFile
    End If
    
    End Sub
    
    intCounter = 0
    
    Do Until IsObject(objIE.document.getElementById("btnLogIn")) = True Or intCounter > 3
    DoEvents
    Application.Wait (Now + TimeValue("0:00:01"))
    intCounter = intCounter + 1
    If intCounter = 4 Then
    MsgBox "Time out."
    End If
    Loop