等待下载完成selenium webdriver JAVA

时间:2014-03-28 13:22:54

标签: java selenium-webdriver

点击下载按钮后,将下载文件。在执行下一个代码之前,需要等到下载完成。 我的代码如下所示:

Thread.sleep(2000);
driver.findElement(By.xpath("//*[@id='perform']")).click();//click for download

Thread.sleep(20000);
//code to be executed after download completes
Readfile fileobj=new Readfile();
String checkfile=fileobj.checkfilename();

如何让webdriver等到下载完成?

13 个答案:

答案 0 :(得分:12)

有点晚了,但这个问题有很多观点,我认为如果你没有继续前进或其他人碰到它,那么值得花些时间来回答它。

我也遇到了同样的问题并且认为我会分享。我当时正在使用python进行开发,但同样的概念适用。您不必使用selenium进行实际下载。您应该考虑检索链接并使用内置函数从那里继续,而不是单击元素以开始下载。

您通常单击以开始下载的元素应该具有您应该能够使用selenium读取的'href'属性。这是指向实际文件的URL。在python中,它看起来像这样:

    element = driver.find_element_by_id('dl_link')
    url = element.get_attribute('href')

从这里您可以使用http库来调用网址。这里的重要部分是你将'stream'设置为true,这样你就可以开始将字节写入文件。确保文件路径包含正确的文件扩展名和其他内容,大多数操作系统不允许您为具有某些字符的文件命名,例如反斜杠或引号,以便对此进行操作。

def download_file(url, file_path):
    from requests import get
    reply = get(url, stream=True)
    with open(file_path, 'wb') as file:
        for chunk in reply.iter_content(chunk_size=1024): 
            if chunk:
                file.write(chunk)

在下载完成之前,程序不应继续,因此在完成之前不再需要轮询。

我为使用其他语言回答道歉,在Java中我相信您可以使用HttpURLConnection API。希望这有帮助!

答案 1 :(得分:6)

我使用Scala进行自动化,但是Java端口应该是微不足道的,因为我总是在那里使用java Selenium类。 所以,首先你需要这个:

import com.google.common.base.Function
import java.nio.file.{Files, Paths, Path}

def waitUntilFileDownloaded(timeOutInMillis:Int)={
    val wait:FluentWait[Path] = new FluentWait(Paths.get(downloadsDir)).withTimeout(timeOutInMillis, TimeUnit.MILLISECONDS).pollingEvery(200, TimeUnit.MILLISECONDS)
    wait.until(
      new Function[Path, Boolean] {
        override def apply(p:Path):Boolean = Files.list(p).iterator.asScala.size > 0
      }
    )
  }

然后在我需要下载xls文件的测试套件中,我就是这样:

def exportToExcel(implicit driver: WebDriver) = {
    click on xpath("//div[contains(@class, 'export_csv')]")
    waitUntilFileDownloaded(2000)
  }

我希望你有这个想法。 FluentWait是非常有用的抽象,虽然它是Selenium的一部分,但它可以在需要等待轮询时使用,直到满足某些条件。

答案 2 :(得分:5)

 $inputXML = @"
<Window x:Class="BlogPostIII.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:BlogPostIII"
        mc:Ignorable="d"
        Title="Organizer" Height="540" Width="540" FontSize="18.667">
    <Grid x:Name="background">
        <Button x:Name="OK" Content="OK" HorizontalAlignment="Left" Height="41" Margin="420,458,0,0" VerticalAlignment="Top" Width="100" FontSize="18.667"/>
        <Button x:Name="Cancel" Content="Cancel" HorizontalAlignment="Left" Height="41" Margin="315,458,0,0" VerticalAlignment="Top" Width="100" FontSize="18.667"/>
        <TextBox x:Name="TextBox1" HorizontalAlignment="Left" Height="30" Margin="108,216,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="300" FontSize="18.667"/>
        <TextBlock x:Name="TextBlock1" HorizontalAlignment="Left" Height="30" Margin="108,36,0,0" TextWrapping="Wrap" Text="Soort bewerking:" VerticalAlignment="Top" Width="300" FontSize="18.667"/>
        <TextBox x:Name="TextBox2" HorizontalAlignment="Left" Height="30" Margin="108,291,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="300" FontSize="18.667"/>
        <TextBlock x:Name="TextBlock2" HorizontalAlignment="Left" Height="30" Margin="108,111,0,0" TextWrapping="Wrap" Text="Naam Machine:" VerticalAlignment="Top" Width="300" FontSize="18.667"/>
        <TextBox x:Name="TextBox3" HorizontalAlignment="Left" Height="30" Margin="108,366,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="300" FontSize="18.667"/>
        <TextBlock x:Name="TextBlock3" HorizontalAlignment="Left" Height="30" Margin="108,185,0,0" TextWrapping="Wrap" Text="Naam van opdrachtgevend bedrijf:" VerticalAlignment="Top" Width="300" FontSize="18.667"/>
        <TextBlock x:Name="TextBlock4" HorizontalAlignment="Left" Height="30" Margin="108,261,0,0" TextWrapping="Wrap" Text="Naam product:" VerticalAlignment="Top" Width="300" FontSize="18.667"/>
        <TextBlock x:Name="TextBlock5" HorizontalAlignment="Left" Height="30" Margin="108,336,0,0" TextWrapping="Wrap" Text="Product ID:" VerticalAlignment="Top" Width="300" FontSize="18.667"/>
        <ComboBox x:Name="combobox1" HorizontalAlignment="Left" Margin="108,66,0,0" VerticalAlignment="Top" Width="300"/>
        <ComboBox x:Name="combobox2" HorizontalAlignment="Left" Margin="108,140,0,0" VerticalAlignment="Top" Width="300"/>
    </Grid>
</Window>
"@        

$inputXML = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N'  -replace '^<Win.*', '<Window'


[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = $inputXML
#Read XAML

    $reader=(New-Object System.Xml.XmlNodeReader $xaml) 
  try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
catch{Write-Host "Unable to load Windows.Markup.XamlReader. Double-check syntax and ensure .net is installed."}

#===========================================================================
# Store Form Objects In PowerShell
#===========================================================================

$xaml.SelectNodes("//*[@Name]") | %{Set-Variable -Name "WPF$($_.Name)" -Value $Form.FindName($_.Name)}

Function Get-FormVariables{
if ($global:ReadmeDisplay -ne $true){Write-host "If you need to reference this display again, run Get-FormVariables" -ForegroundColor Yellow;$global:ReadmeDisplay=$true}
write-host "Found the following interactable elements from our form" -ForegroundColor Cyan
get-variable WPF*
}

Get-FormVariables

#===========================================================================
# List the Comboboxes
#===========================================================================

$WPFcombobox1.AddText('Draaien')
$WPFcombobox1.AddText('Frezen')
$WPFcombobox1.AddText('Slijpen')

$WPFcombobox2.AddText('Doosan 3100LM')
$WPFcombobox2.AddText('Doosan 123')
$WPFcombobox2.AddText('machine 3')
$WPFcombobox2.AddText('machine 4')
$WPFcombobox2.AddText('machine 5')


#===========================================================================
# Actually make the objects work
#===========================================================================


#$WPFMakeUserbutton.Add_Click({(Get-FormFields)})


$WPFOK.Add_Click({
    $1 = $WPFcomboBox1.Text
    $2 = $WPFcomboBox2.Text
    $3 = $WPFtextBox1.Text
    $4 = $WPFtextBox2.Text
    $5 = $WPFtextBox3.Text + " Werkblad"
    New-Item C:\Users\Bjorn\Documents\Powershell\$1\$2\$3\$4\ -Force -type directory
    Copy-Item C:\Users\Bjorn\Documents\Powershell\Test_werkblad.docx C:\Users\Bjorn\Documents\Powershell\$1\$2\$3\$4\
    Rename-Item C:\Users\Bjorn\Documents\Powershell\$1\$2\$3\$4\Test_werkblad.docx C:\Users\Bjorn\Documents\Powershell\$1\$2\$3\$4\$5.docx
    Invoke-Item C:\Users\Bjorn\Documents\Powershell\$1\$2\$3\$4
    Invoke-Item C:\Users\Bjorn\Documents\Powershell\$1\$2\$3\$4\$5.docx
    $Form.Close()})

$WPFCancel.Add_Click({
    $Form.Close()})


#===========================================================================
# Shows the form
#===========================================================================
write-host "To show the form, run the following" -ForegroundColor Cyan

function Show-Form{
$Form.ShowDialog() | out-null

}

Show-Form

其中f是文件,filesize很长

答案 3 :(得分:3)

好吧,你的文件存放在某个地方,对吧?因此,请检查文件系统中是否存在

File f = new File(filePathString);

do {
  Thread.sleep(3000);
} while (f.exists() && f.length() == expectedSizeInBytes)

答案 4 :(得分:3)

对亚历山大·阿伦达的想法的改编:

(使用Java 8&amp; FluentWait的until方法的谓词版本)

  private void waitForFileDownload(int totalTimeoutInMillis, String expectedFileName) throws IOException {  
            FluentWait<WebDriver> wait = new FluentWait(this.funcDriver.driver)
                                   .withTimeout(totalTimeoutInMillis, TimeUnit.MILLISECONDS)
                                   .pollingEvery(200, TimeUnit.MILLISECONDS);
            File fileToCheck = getDownloadsDirectory()
                               .resolve(expectedFileName)
                               .toFile();

            wait.until((WebDriver wd) -> fileToCheck.exists());

        }


public synchronized Path getDownloadsDirectory(){
        if(downloadsDirectory == null){

            try {
                downloadsDirectory = Files.createTempDirectory("selleniumdownloads_");
            } catch (IOException ex) {
                throw new RuntimeException("Failed to create temporary downloads directory");
            }
        }
        return downloadsDirectory;
    }

请注意使用createTempDirectory来避免递归删除超过预期的警告以及在我们完成它时自动安全地处理文件夹。

答案 5 :(得分:1)

某些操作系统(例如Mac OS X)在下载完成之前不会设置文件名。因此,使用wait或while循环检查文件是否存在似乎已足够。

e.g。

File file = new File(fullPathToFile);
while (!file.exists()) {
    Thread.sleep(1000);
}

答案 6 :(得分:1)

我喜欢awaitility

    Path filePath = Paths.get(".", "filename");
    await().atMost(1, MINUTES)
            .ignoreExceptions()
            .until(() -> filePath.toFile().exists());

更多信息:http://www.testautomationguru.com/selenium-webdriver-how-to-wait-for-expected-conditions-using-awaitility/

答案 7 :(得分:1)

如果您使用chrome下载,则可以使用以下方法来确保脚本将等待下载完成。

Python实现:

def waitUntilDownloadCompleted(maxTime=600):
    driver.execute_script("window.open()")
    # switch to new tab
    driver.switch_to.window(driver.window_handles[-1])
    # navigate to chrome downloads
    driver.get('chrome://downloads')
    # define the endTime
    endTime = time.time() + maxTime
    while True:
        try:
            # get the download percentage
            downloadPercentage = driver.execute_script(
                "return document.querySelector('downloads-manager').shadowRoot.querySelector('#downloadsList downloads-item').shadowRoot.querySelector('#progress').value")
            # check if downloadPercentage is 100 (otherwise the script will keep waiting)
            if downloadPercentage == 100:
                # exit the method once it's completed
                return downloadPercentage
        except:
            pass
        # wait for 1 second before checking the percentage next time
        time.sleep(1)
        # exit method if the download not completed with in MaxTime.
        if time.time() > endTime:
            break

只要单击下载链接/按钮,就调用该方法。

# click on download button
driver.find_element_by_xpath("//*[@id='perform']").click()
#wait until the download completed
waitUntilDownloadCompleted(120) #2 minutes

答案 8 :(得分:0)

以下代码对我来说很好用。

也不会出现警告,因为我按照建议使用了通用类型和持续时间。

File file = new File(“ C:\ chromedriver_win32.zip”); FluentWait wait =新的FluentWait(driver).withTimeout(Duration.ofSeconds(25))。pollingEvery(Duration.ofMillis(100)); wait.until(x-> file.exists());

答案 9 :(得分:0)

import time
from os import walk

download_dir = 'path\\to\\download\\folder'


def check_if_download_folder_has_unfinished_files():
    for (dirpath, dirnames, filenames) in walk(download_dir):
        return str(filenames)


def wait_for_files_to_download():
    time.sleep(5)  # let the driver start downloading
    file_list = check_if_download_folder_has_unfinished_files()
    while 'Unconfirmed' in file_list or 'crdownload' in file_list:
        file_list = check_if_download_folder_has_unfinished_files()
        time.sleep(1)


if __name__ == '__main__':
    wait_for_files_to_download()

答案 10 :(得分:0)

这个为我工作:

    Path filePath = Paths.get("path/to/file/fileName.pdf");
    File file = filePath.toFile(); 

 void waitForFileDownloaded(File file, int timeoutSeconds) {
        WebDriver driver = getDriver();
        FluentWait<WebDriver> wait = new FluentWait<>(driver)
                .withTimeout(Duration.ofSeconds(timeoutSeconds))
                .pollingEvery(Duration.ofMillis(500))
                .ignoring(NoSuchElementException.class, StaleElementReferenceException.class);
        wait.until((webDriver) -> file.exists());
    }

答案 11 :(得分:0)

此代码将始终有效。请尝试一下!

public void waitForFileDownloaded(String fileName, int timeoutSeconds) {
    FluentWait<WebDriver> wait = new FluentWait<>(driver)
            .withTimeout(Duration.ofSeconds(timeoutSeconds))
            .pollingEvery(Duration.ofMillis(500))
            .ignoring(NoSuchElementException.class, StaleElementReferenceException.class);
    wait.until((x) -> {
        File[] files = new File(downloadfolderPath).listFiles();
        for (File file : files) {
            if (file.getName().contains(fileName)) {
                return true;
            }
        }
        return false;
    });
}

答案 12 :(得分:0)

这里仅使用WebDriverWait:

new WebDriverWait(driver, 60).until(d -> Paths.get(downloadDir, downloadFileName).toFile().exists());