基本上,我至少要检查是否存在可下载的文件/下载链接是否正常工作,并且最好能获得类似文件大小的信息。

这里是一个示例:

link = self.browser.find_element_by_link_text('link text')
href = link.get_attribute('href')
download = self.browser.get(href)
print download


第四行打印“ None”,大概是因为我没有手动单击“保存”按钮,即使我有,我怀疑WebDriver是否能够“看到”该文件。

有什么想法吗?我正在使用Firefox作为被测浏览器,并且我了解下载的文件处理在某种程度上是特定于浏览器和/或操作系统的。

评论

也许最好看一下[this] [1]。 [1]:stackoverflow.com/questions/18439851/…

这有效:使用geb.Page
downloadBytes($(selector)[0]。@ href)
一种可能的解决方案是通过Selenium获取文件的URL,创建(非Selenium)连接,将Selenium的cookie复制到该连接(如果需要),然后下载文件。由于此方法利用非Selenium API来下载文件,因此它可以与(或不与)任何浏览器一起使用。有关更多信息,请参见这里我的答案:stackoverflow.com/questions/16746707/…

#1 楼

据我所知,没有简单的方法来制作Selenium下载文件,因为浏览器为此使用了本机对话框,而这些本机对话框无法由JavaScript控制,因此您需要一些“技巧”。对此进行检查,希望对您有所帮助。

评论


谢谢。我可能会尝试使用Python请求模块来做到这一点。

–亚伦剃须刀
2011-12-22 22:05

+1,但“提供链接上下文鼓励使用外部资源链接,但请在链接周围添加上下文,以便您的其他用户可以了解链接的含义和含义。始终在其中引用重要链接的最相关部分如果目标站点无法访问或永久脱机。”如此处所述:sqa.stackexchange.com/help/how-to-answer

– dzieciou
14年6月28日在17:53

#2 楼

这是一个解决方案。将Firefox的首选项设置为自动保存,并且不弹出下载窗口。然后,您只需抓取文件,便会下载该文件。

所以,像这样的东西:下载目录,从不要求保存,也没有下载管理器出现,从这一点来看,自动化应该很简单。

评论


像魅力一样工作,但是我使用了我的用户个人资料。 stackoverflow.com/questions/15954682/…

–jmunsch
2014年4月27日在23:13

这个答案应该仍然可以在Firefox 58上使用吗?我无法使其正常运行。

–融化
18年1月1日在10:12

我们已经在Firefox 47之前的版本中使用了很长时间,并且效果很好。现在我们已经升级到58,它不再起作用。

–k-den
18 Mar 30 '18 at 20:15

在这里,它仍然/再次使用以下设置工作:profile.setPreference(“ browser.download.dir”,“ path \\ ...”); profile.setPreference(“ browser.download.folderList”,2); profile.setPreference(“ browser.helperApps.neverAsk.saveToDisk”,“文本/纯文本”);

– Clerenz
19年5月6日15:31



@ k-den,以防万一您错过了最新评论

–马克·梅奥(Mark Mayo)
19年5月7日在23:09

#3 楼

首先,为什么要下载文件?您打算用它做任何事情吗?

大多数想要下载文件的人都这样做了,以便他们可以显示一个自动化框架来下载文件,因为它使某人变得非技术性。

您可以检查标题响应以检查是否获得200 OK(或者重定向,取决于您的预期结果),它会告诉您文件已存在。

仅下载文件(如果您实际上要对它们进行处理),如果下载文件是为了这样做,那是在浪费测试时间,网络带宽和磁盘空间。

这是我的实现。

这将找到页面上的链接并提取要链接的URL。然后,它使用apache commons复制selenium使用的浏览器会话,然后下载文件。在某些情况下,它将无法工作(页面上的链接实际上并未链接到下载文件,而是一个阻止自动文件下载的层)。

通常,它可以正常工作,并且是跨平台/跨浏览器兼容。

代码是:

      /*
      * Copyright (c) 2010-2011 Ardesco Solutions - http://www.ardescosolutions.com
      *
      * Licensed under the Apache License, Version 2.0 (the "License");
      * you may not use this file except in compliance with the License.
      * You may obtain a copy of the License at
      *
      * http://www.apache.org/licenses/LICENSE-2.0
      *
      * Unless required by applicable law or agreed to in writing, software
      * distributed under the License is distributed on an "AS IS" BASIS,
      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      * See the License for the specific language governing permissions and
      * limitations under the License.
      */

    package com.lazerycode.ebselen.customhandlers;

    import com.google.common.annotations.Beta;
    import com.lazerycode.ebselen.EbselenCore;
    import com.lazerycode.ebselen.handlers.FileHandler;
    import org.apache.commons.httpclient.*;
    import org.apache.commons.httpclient.cookie.CookiePolicy;
    import org.apache.commons.httpclient.HttpClient;
    import org.apache.commons.httpclient.methods.GetMethod;

    import java.io.*;
    import java.net.URL;
    import java.util.Set;

    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebElement;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    @Beta
    public class FileDownloader {

        private static final Logger LOGGER = LoggerFactory.getLogger(EbselenCore.class);
        private WebDriver driver;
        private String downloadPath = System.getProperty("java.io.tmpdir");

        public FileDownloader(WebDriver driverObject) {
            this.driver = driverObject;
        }

        /**
         * Get the current location that files will be downloaded to.
         *
         * @return The filepath that the file will be downloaded to.
         */
        public String getDownloadPath() {
            return this.downloadPath;
        }

        /**
         * Set the path that files will be downloaded to.
         *
         * @param filePath The filepath that the file will be downloaded to.
         */
        public void setDownloadPath(String filePath) {
            this.downloadPath = filePath;
        }


        /**
         * Load in all the cookies WebDriver currently knows about so that we can mimic the browser cookie state
         *
         * @param seleniumCookieSet
         * @return
         */
        private HttpState mimicCookieState(Set<org.openqa.selenium.Cookie> seleniumCookieSet) {
            HttpState mimicWebDriverCookieState = new HttpState();
            for (org.openqa.selenium.Cookie seleniumCookie : seleniumCookieSet) {
                Cookie httpClientCookie = new Cookie(seleniumCookie.getDomain(), seleniumCookie.getName(), seleniumCookie.getValue(), seleniumCookie.getPath(), seleniumCookie.getExpiry(), seleniumCookie.isSecure());
                mimicWebDriverCookieState.addCookie(httpClientCookie);
            }
            return mimicWebDriverCookieState;
        }

        /**
         * Mimic the WebDriver host configuration
         *
         * @param hostURL
         * @return
         */
        private HostConfiguration mimicHostConfiguration(String hostURL, int hostPort) {
            HostConfiguration hostConfig = new HostConfiguration();
            hostConfig.setHost(hostURL, hostPort);
            return hostConfig;
        }

        public String fileDownloader(WebElement element) throws Exception {
            return downloader(element, "href");
        }

        public String imageDownloader(WebElement element) throws Exception {
            return downloader(element, "src");
        }

        public String downloader(WebElement element, String attribute) throws Exception {
            //Assuming that getAttribute does some magic to return a fully qualified URL
            String downloadLocation = element.getAttribute(attribute);
            if (downloadLocation.trim().equals("")) {
                throw new Exception("The element you have specified does not link to anything!");
            }
            URL downloadURL = new URL(downloadLocation);
            HttpClient client = new HttpClient();
            client.getParams().setCookiePolicy(CookiePolicy.RFC_2965);
            client.setHostConfiguration(mimicHostConfiguration(downloadURL.getHost(), downloadURL.getPort()));
            client.setState(mimicCookieState(driver.manage().getCookies()));
            HttpMethod getRequest = new GetMethod(downloadURL.getPath());
            FileHandler downloadedFile = new FileHandler(downloadPath + downloadURL.getFile().replaceFirst("/|\\", ""), true);
            try {
                int status = client.executeMethod(getRequest);
                LOGGER.info("HTTP Status {} when getting '{}'", status, downloadURL.toExternalForm());
                BufferedInputStream in = new BufferedInputStream(getRequest.getResponseBodyAsStream());
                int offset = 0;
                int len = 4096;
                int bytes = 0;
                byte[] block = new byte[len];
                while ((bytes = in.read(block, offset, len)) > -1) {
                    downloadedFile.getWritableFileOutputStream().write(block, 0, bytes);
                }
                downloadedFile.close();
                in.close();
                LOGGER.info("File downloaded to '{}'", downloadedFile.getAbsoluteFile());
            } catch (Exception Ex) {
                LOGGER.error("Download failed: {}", Ex);
                throw new Exception("Download failed!");
            } finally {
                getRequest.releaseConnection();
            }
            return downloadedFile.getAbsoluteFile();
        }
    }
 


评论


只是好奇,这对HTTPS有用吗?我想不,因为您的HttpClient配置中不支持SSL ...

– dzieciou
14年6月28日在17:51

它应该可以工作(hc.apache.org/httpclient-3.x/sslguide.html),但是http客户端库现在已停产,因此最好使用HTTP组件库hc.apache.org/httpcomponents-client-ga /examples.html

– Ardesco
2014年6月30日下午6:31

我想下载一个文件来检查它是否包含正确的数据。

–安德斯·林登(AndersLindén)
19年8月14日在6:13

这不适用于HttpOnly cookie吗?

–Ákos Vandra
3月1日17:50

用一种奇怪的想法来回答一个问题:“您可能不需要这样做”。有时我们需要做些事情。是因为他们说得通还是因为老板这么说。让我的老板闹,啊,付账单。因此,这是有原因的。想象一下,被困住了,有人告诉您您的整个前提是在浪费时间。至于解决方案,我也不同意这是一个主意。大多数文件是动态生成或动态引用的,您没有“ storage.com/myfile.txt” ...这通常是Java脚本操作或某种魔术(我不是浏览器程序员)

– DraxDomax
12月10日的3:48

#4 楼

我发现最好的方法是访问页面,获取下载链接,并使用HTTP库对文件执行HEAD请求。响应将包含文件的长度及其类型。
最好使用HEAD请求,因为它只会检索标头而不是拉下整个文件。
如果文件位于auth后面,则您将需要在执行请求时从Selenium的cookie存储中提取会话cookie,并将其传递到HTTP库。
,或者您可以配置用于将文件自动下载到特定位置的浏览器,然后对磁盘上的文件执行检查。
我在这里用工作的Ruby代码详细介绍了每种方法:用于安全文件


评论


通常,这很好,只要页面不需要登录即可。用户必须登录后,该解决方案才会中断。

– andreas
17年11月27日在15:57

#5 楼

这种方法怎么样:

如何使用自定义Firefox配置文件自动保存文件?

评论


跨平台和Python。这是最好的方法。

–塞林
2012年10月29日12:06

不鼓励仅链接的答案。请从链接中将解决方案部分添加到您的答案中。

–小熊猫
15年4月28日在15:57

#6 楼

通过使用ajax请求并返回字节,我制作了自己的下载器版本。具有直接使用浏览器的优点,因此不需要处理身份验证和cookie。缺点是受同源规则限制,它可能需要大量内存,并且在旧的浏览器中也可能会失败。

有时还是很有用的:

import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;

public class AjaxFileDownloader {

    private WebDriver driver;

    public AjaxFileDownloader(WebDriver driverObject) {
        this.driver = driverObject;
        driver.manage().timeouts().setScriptTimeout(15, TimeUnit.SECONDS); // maybe you need a different timeout
    }

    public InputStream download(String url) throws IOException {
        String script = "var url = arguments[0];" +
                "var callback = arguments[arguments.length - 1];" +
                "var xhr = new XMLHttpRequest();" +
                "xhr.open('GET', url, true);" +
                "xhr.responseType = \"arraybuffer\";" + //force the HTTP response, response-type header to be array buffer
                "xhr.onload = function() {" +
                "  var arrayBuffer = xhr.response;" +
                "  var byteArray = new Uint8Array(arrayBuffer);" +
                "  callback(byteArray);" +
                "};" +
                "xhr.send();";
        Object response = ((JavascriptExecutor) driver).executeAsyncScript(script, url);
        // Selenium returns an Array of Long, we need byte[]
        ArrayList<Long> byteList = (ArrayList<Long>) response;
        byte[] bytes = new byte[byteList.size()];
        for(int i = 0; i < byteList.size(); i++) {
            bytes[i] = (byte)(long)byteList.get(i);
        }
        return new ByteArrayInputStream(bytes);
    }

}


评论


惊人的效果很好,非常感谢您提供的最新答案!

– ibiza
17年5月25日在0:11

我通过将responsetype设置为“ text”并在没有数组内容的情况下进行了回调,对此进行了一些修改。它工作得很漂亮。我需要它的csv文件。

–user890332
19年2月19日在18:25

#7 楼

这篇博客文章描述了一种直接方法,即调用另一个库来下载文件(而不是通过浏览器),同时保持硒与站点的会话-因此,它可用于受密码保护的文件等。

评论


我已经意识到这类似于Ardesco的答案。但是,我认为博客文章中的解决方案更简单。而且,它用于.NET而不是Java,因此对于针对该平台的人们而言可能很有用。

–马丁·伊甸园
2012年6月11日17:21

仅Windows?布拉赫

–塞林
2012年10月29日在12:03

#8 楼

在Selenium中有很多下载文件的方法,这是使用Firefox Profile在Firefox中最简单的方法之一。 。

我发现以下有趣的文章涵盖了上述情况

http://learn-automation.com/how-to-download-files-using-selenium-webdriver/

#9 楼

首先,考虑一下-您真的需要下载图片吗?或者您只需要确保它存在并且可以下载?

您可能会在这里找到完整的受信任描述,只需跟随图像的URL即可检查图像是否可用和存在。

主要步骤是:

提取授权cookie(如果需要用户会话)
使用它们来建立新的HTTP请求
发送带有图像URL的此类请求检查状态码
如果状态码为200-图像是否存在

要获取类似webDriver的cookie,只需使用以下方法:

webDriver.manage().getCookieNamed("JSESSIONID");


请注意,它不是类似apache的cookie,因此不能严格将它们与apache http客户端一起使用。但是您可以基于它构建一个类似Apache的文件。

评论


欢迎来到sqa.stackexchange.com。这是一个非常详细的答案,但是OP很清楚要下载文档而不是检查图像。当回答问题的地址时,答案是最有效的。

–丹·斯内尔(Dan Snell)
13年2月20日在23:21

抱歉! :)))我非常着迷于寻找有关如何检查图像是否存在的方法,该方法过于关注图像而错过了“文档”。好的,无论如何-我认为下载文件应该完全相同。感谢您的评论

–小工具
13年2月21日在8:12

#10 楼

我最近采用的一种方法是通过提琴手捕捉响应。就我而言,我直接在应用程序中调用导出处理程序。我包裹了硒位,并用提琴手核心拦截了流量。我实际上只是关心文件中的数据,而不是浏览器正确地解释了请求。您还可以使用单击动作来完成此操作。

        static string Test2ExportGeneration()
    {
        IWebDriver driver = new InternetExplorerDriver();
        FiddlerApplication.Startup(8877, true, true);

        List<Session> oAllSessions = new List<Session>();

        LoginPage login = new LoginPage(driver);
        //PerformancePage perf = new PerformancePage(driver);

        FiddlerApplication.AfterSessionComplete += delegate(Session oS)
        {
            Monitor.Enter(oAllSessions);
            oAllSessions.Add(oS);
            Monitor.Exit(oAllSessions);
        };

        driver.Navigate().GoToUrl(test2BaseURL + "login.aspx");
        login.LoginToView("test123@test123.com", "pw");
        driver.Navigate().GoToUrl(test2BaseURL + "/handlers/export.ashx?id=74&accountId=164");

        FiddlerApplication.Shutdown();

        driver.Quit();
        string responseBody = "";

        foreach (Session oS in oAllSessions)
        {
            if (oS.fullUrl.Contains("handlers"))
            {
                oS.utilDecodeResponse();
                string type = oS.oResponse.MIMEType;

                responseBody = oS.GetResponseBodyAsString();

            }
        }

        return responseBody;

    }


FiddlerCore中的GetResponseBodyAsString()方法将响应拆包并返回一个字符串,我可以对其进行操作和使用在代码中。

我正在使用C#和Webdriver进行实施。如果您使用其他语言,我认为还有其他一些工具。我认为这样做的好处是,我可以不必尝试与任何浏览器的文件下载机制进行交互。如果以后要创建文件,浏览器将收到的所有信息都在响应标头中。

评论


很棒的方法。但是,在浏览器中,一旦开始下载,您仍然必须处理所有本机下载对话框。人们可能不得不将您的方法与诸如自动保存下载文件之类的东西结合起来(sqa.stackexchange.com/a/6317/17012)

– Peter Wippermann
16-3-2在11:31

在这种情况下,我根本不关心如何处理警报。我只是将数据读入内存,然后从那里进行工作并进行了验证。我从未真正将其读取到磁盘。如果我真的想使用该文件,则只需使用write.File或其他代码机制将其保存,然后将浏览器一起传递。毕竟我没有测试浏览器文件处理。完成后,我只是简单地终止了浏览器会话。

–丹·斯内尔(Dan Snell)
16年4月13日在16:58

#11 楼

一个简单但有些脆弱的解决方案(取决于您是否期望目标环境中的屏幕尺寸一致);可以使用如下所示的java.awt.Robot类。如我所见,chrome没有用于确认下载的操作系统对话框。

//add wait time to for file download dialogue to appear
    Sleeper.SYSTEM_SLEEPER.sleep(new Duration(5,java.util.concurrent.TimeUnit.SECONDS));
    Robot r = new Robot();
    r.mouseMove(888, 458);//coordinates of save button
    //focus dialogue window
    r.mousePress(InputEvent.BUTTON1_MASK);
    r.mouseRelease(InputEvent.BUTTON1_MASK);
    Sleeper.SYSTEM_SLEEPER.sleep(new Duration(1,java.util.concurrent.TimeUnit.SECONDS));
    //click save button
    r.mousePress(InputEvent.BUTTON1_MASK);
    r.mouseRelease(InputEvent.BUTTON1_MASK);
    //wait for file to download
    Sleeper.SYSTEM_SLEEPER.sleep(new Duration(5,java.util.concurrent.TimeUnit.SECONDS));


#12 楼

我们完成此操作的方法是将密钥发送到浏览器窗口。同意它不是最好的解决方案,但它是快捷有效的。我们使用IE的硒Web驱动程序在IE9上完成了此操作,我们要自动化的方案是单击“提交”按钮,最终会在浏览器上下载文件。

我们完成此操作的方法是在线程上单击“提交”,因为在执行操作以进度或取消下载栏上的下载之前,提交一直处于阻塞状态。然后等待几秒钟,然后将Tab键发送到浏览器,最终结束对“保存”按钮的关注(如果您只想保存IE中的默认位置,则发送ALT + S即可),但在本例中,我们希望保存在特定位置具有特定名称的文件。按下保存按钮后,请发送向下箭头键,以打开保存按钮上的菜单,然后再按几个向下箭头键,然后按Enter键打开另存为对话框。以下是代码片段(用C#编写):

 Thread ts = new Thread(new ThreadStart(()=> submitButton.click();));
 ts.start();
 System.Threading.Thread.Sleep(5000);
 System.Windows.Forms.SendKeys.SendWait("{TAB}");
 System.Threading.Thread.Sleep(1000);
 System.Windows.Forms.SendKeys.SendWait("{TAB}");
 System.Threading.Thread.Sleep(1000);
 System.Windows.Forms.SendKeys.SendWait("{TAB}");
 System.Threading.Thread.Sleep(1000);
 System.Windows.Forms.SendKeys.SendWait("{DOWN}");
 System.Threading.Thread.Sleep(1000);
 System.Windows.Forms.SendKeys.SendWait("{DOWN}");
 System.Threading.Thread.Sleep(1000);
 System.Windows.Forms.SendKeys.SendWait("{ENTER}");
 System.Threading.Thread.Sleep(1000);


“保存”对话框打开。发送更多键以写入文件名,然后发送ALT + S进行下载。

#13 楼

当您将Selenium Web驱动程序用于firefox配置文件时,处理模式窗口的最佳方法是更改​​firefox配置文件设置,以将文件自动下载到所需位置。

这里的其他答案具有有用的信息,但没有基于JAVA的有效解决方案。

这是一段像技巧一样起作用的代码段-

FirefoxProfile profile = new FirefoxProfile();          
profile.setPreference("browser.download.folderList",2);
profile.setPreference("browser.download.manager.showWhenStarting",false);
profile.setPreference("browser.download.dir","C\downloads");
profile.setPreference("browser.helperApps.neverAsk.saveToDisk", 
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;"
+ "application/pdf;" 
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document;" 
+ "text/plain;" 
+ "text/csv");  
Webdriver driver = new FirefoxDriver(profile);


#14 楼

SCALA:

val remote = new RemoteWebDriver(new URL("http://localhost:9515/"),
DesiredCapabilities.chrome())
val a =  remote.findElements(By.xpath("""//td[6]/a[2]""")).iterator()

while(a.hasNext){   
  val xmlclick = a.next()   
  println("a href: " + xmlclick.getAttribute("href") + "; "+ xmlclick.getText  )  
  xmlclick.click()   
  Thread.sleep(1000) 
}


要进行全自动工作,您需要阅读以下有关DesiredCapabilities的信息:https://stackoverflow.com/questions/23510816/how-to-handle-在硒网络驱动程序中下载文件