【问题标题】:Download file using HtmlUnit使用 HtmlUnit 下载文件
【发布时间】:2012-10-21 12:38:02
【问题描述】:

我正在尝试为网站下载 xls 文件。当我单击链接下载文件时,我得到一个 javascript 确认框。我像下面这样处理它

    ConfirmHandler okHandler = new ConfirmHandler(){
            public boolean handleConfirm(Page page, String message) {
                return true;
            }
        };
    webClient.setConfirmHandler(okHandler);

有一个下载文件的链接。

<a href="./my_file.php?mode=xls&amp;w=d2hlcmUgc2VsbElkPSd3b3JsZGNvbScgYW5kIHN0YXR1cz0nV0FJVERFTEknIGFuZCBkYXRlIDw9IC0xMzQ4MTUzMjAwICBhbmQgZGF0ZSA%2BPSAtMTM1MDgzMTU5OSA%3D" target="actionFrame" onclick="return confirm('Do you want do download XLS file?')"><u>Download</u></a>

我点击链接使用

HTMLPage x = webClient.getPage("http://working.com/download");
HtmlAnchor anchor = (HtmlAnchor) x.getFirstByXPath("//a[@target='actionFrame']");
anchor.click();

handeConfirm() 方法被执行。但我不知道如何从服务器保存文件流。我尝试使用下面的代码查看流。

anchor.click().getWebResponse().getContentAsString();

但是,结果与页面 x 相同。任何人都知道如何从服务器捕获流?谢谢。

【问题讨论】:

标签: download htmlunit


【解决方案1】:

我找到了一种使用 WebWindowListener 获取 InputStream 的方法。在 webWindowContentChanged(WebWindowEvent event) 里面,我把代码放在下面。

InputStream xls = event.getWebWindow().getEnclosedPage().getWebResponse().getContentAsStream();

获得 xls 后,我可以将文件保存到我的硬盘中。

【讨论】:

  • 我正在下载一个 csv 文件,你能解释一下什么是事件以及你什么时候在锚点上调用点击事件。我没有下载文件的确认框。
  • @Naveen 这与上面描述的完全一样,除了.getContentAsStream() 你将使用getContentAsString() 然后你可以String.split("\n") 来获取单独的行,然后将这些行拆分一次再次使用String.split(",") 获取每一行的信息。
【解决方案2】:

我是根据您的帖子制作的。注意:您可以更改内容类型条件以仅下载特定类型的文件。例如(应用程序/octect-stream、应用程序/pdf 等)。

package net.s4bdigital.export.main;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;

import com.gargoylesoftware.htmlunit.ConfirmHandler;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.WebResponse;
import com.gargoylesoftware.htmlunit.WebWindowEvent;
import com.gargoylesoftware.htmlunit.WebWindowListener;
import com.gargoylesoftware.htmlunit.util.NameValuePair;

public class HtmlUnitDownloadFile {

    protected String baseUrl;
    protected static WebDriver driver;

    @Before
    public void openBrowser() {
        baseUrl = "http://localhost/teste.html";
        driver = new CustomHtmlUnitDriver();
        ((HtmlUnitDriver) driver).setJavascriptEnabled(true);

    }


    @Test
    public void downloadAFile() throws Exception {

        driver.get(baseUrl);
        driver.findElement(By.linkText("click to Downloadfile")).click();

    }

    public class CustomHtmlUnitDriver extends HtmlUnitDriver { 

          // This is the magic. Keep a reference to the client instance 
           protected WebClient modifyWebClient(WebClient client) { 


             ConfirmHandler okHandler = new ConfirmHandler(){
                    public boolean handleConfirm(Page page, String message) {
                        return true;
                    }
             };
             client.setConfirmHandler(okHandler);

             client.addWebWindowListener(new WebWindowListener() {

                public void webWindowOpened(WebWindowEvent event) {
                    // TODO Auto-generated method stub

                }

                public void webWindowContentChanged(WebWindowEvent event) {

                    WebResponse response = event.getWebWindow().getEnclosedPage().getWebResponse();
                    System.out.println(response.getLoadTime());
                    System.out.println(response.getStatusCode());
                    System.out.println(response.getContentType());

                    List<NameValuePair> headers = response.getResponseHeaders();
                    for(NameValuePair header: headers){
                        System.out.println(header.getName() + " : " + header.getValue());
                    }

                    // Change or add conditions for content-types that you would to like 
                    // receive like a file.
                    if(response.getContentType().equals("text/plain")){
                        getFileResponse(response, "target/testDownload.war");
                    }



                }

                public void webWindowClosed(WebWindowEvent event) {



                }
            });          

             return client; 
           } 


    } 

    public static void getFileResponse(WebResponse response, String fileName){

        InputStream inputStream = null;

        // write the inputStream to a FileOutputStream
        OutputStream outputStream = null; 

        try {       

            inputStream = response.getContentAsStream();

            // write the inputStream to a FileOutputStream
            outputStream = new FileOutputStream(new File(fileName));

            int read = 0;
            byte[] bytes = new byte[1024];

            while ((read = inputStream.read(bytes)) != -1) {
                outputStream.write(bytes, 0, read);
            }

            System.out.println("Done!");

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outputStream != null) {
                try {
                    // outputStream.flush();
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }

    }

}

【讨论】:

  • 对不起,我不明白,你在哪里或如何在modifywebclient 方法中保留对webclient 的引用......谢谢
  • selenium.googlecode.com/svn/trunk/docs/api/java/org/openqa/…Anudeep Samaiya 是超类的一个方法。我们可以覆盖它,添加一个句柄来确认下载文件的窗​​口。但是你需要修改内容类型等待你的情况。
  • 我遇到了一个问题,比如下载文件但不完整。文件内容是一半。
  • @viralpatel 我从来没有遇到过,但是我有一个线索,您是否已经在我们的特定案例中验证了 http 响应中的“Content-Length”标头?对吗?
  • @EduardoFabricio 你能指导我如何验证“Content-Length”标头。实际上,当我手动下载文件或使用 chrome 驱动程序时,我正在尝试下载具有 101 行的文件,但是当我尝试使用 HTML 单元时,它只有 70 行。
【解决方案3】:

如果您不想用 Selenium 包装 HtmlUnit,那么还有一种更简单的方法。只需为 HtmlUnit 的 WebClient 提供扩展的 WebWindowListener。

您还可以使用 Apache commons.io 轻松进行流复制。

WebClient webClient = new WebClient();
webClient.addWebWindowListener(new WebWindowListener() {
    public void webWindowOpened(WebWindowEvent event) { }

    public void webWindowContentChanged(WebWindowEvent event) {
        // Change or add conditions for content-types that you would
        // to like receive like a file.
        if (response.getContentType().equals("text/plain")) {
            try {
                IOUtils.copy(response.getContentAsStream(), new FileOutputStream("downloaded_file"));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    public void webWindowClosed(WebWindowEvent event) {}
});

【讨论】:

  • 如何在 webWindowContentChanged 方法中得到响应?
【解决方案4】:
 final WebClient webClient = new WebClient(BrowserVersion.CHROME);
        webClient.getOptions().setTimeout(2000);
        webClient.getOptions().setThrowExceptionOnScriptError(false);
        webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
        webClient.waitForBackgroundJavaScript(2000);

        //get General page
        final HtmlPage page = webClient.getPage("http://your");

        //get Frame
        final HtmlPage frame = ((HtmlPage) 
        page.getFrameByName("Frame").getEnclosedPage());

        webClient.setConfirmHandler(new ConfirmHandler() {
            public boolean handleConfirm(Page page, String message) {
                return true;
            }
        });

        //get element file
        final DomElement file = mainFrame.getElementByName("File");

        final InputStream xls =  file.click().getWebResponse().getContentAsStream();

        assertNotNull(xls);
    }

【讨论】:

    【解决方案5】:

    扩展罗伊的答案,这是我对这个问题的解决方案:

    public static void prepareForDownloadingFile(WebClient webClient, File output) {
        webClient.addWebWindowListener(new WebWindowListener() {
    
            public void webWindowOpened(WebWindowEvent event) {
            }
    
            public void webWindowContentChanged(WebWindowEvent event) {
                Page page = event.getNewPage();
                FileOutputStream fos = null;
                InputStream is = null;
                if (page != null && page instanceof UnexpectedPage) {
                    try {
                        fos = new FileOutputStream(output);
                        UnexpectedPage uPage = (UnexpectedPage) page;
                        is = uPage.getInputStream();
                        IOUtils.copy(is, fos);
                        webClient.removeWebWindowListener(this);
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            if (fos != null)
                                fos.close();
                            if (is != null)
                                is.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
    
            }
    
            public void webWindowClosed(WebWindowEvent event) {
            }
        });
    }
    

    我觉得有足够的差异使它成为一个新的答案:
    -没有魔法变量 (response)
    -关闭 InputStreamFileOutputStream
    - 查找 UnexpectedPage 以确定我们不在 HTML 页面上
    - 请求后下载一次文件,然后自行删除
    - 不需要知道ContentType

    在此之前调用一次,例如,单击启动下载的按钮,将下载该文件。

    【讨论】:

      【解决方案6】:

      找出下载 URL,并将其抓取到 List 中。从下载网址我们可以使用此代码获取整个文件。

          try{
              String path = "your destination path";
              List<HtmlElement> downloadfiles = (List<HtmlElement>) page.getByXPath("the tag you want to scrape");
              if (downloadfiles.isEmpty()) {
                  System.out.println("No items found !");
              } else {
                  for (HtmlElement htmlItem : downloadfiles) {
                      String DownloadURL = htmlItem.getHrefAttribute();
      
                      Page invoicePdf = client.getPage(DownloadURL);
                      if (invoicePdf.getWebResponse().getContentType().equals("application/pdf")) {
                          System.out.println("creatign PDF:");
                          IOUtils.copy(invoicePdf.getWebResponse().getContentAsStream(),
                                  new FileOutputStream(path + "file name"));
                      }
                  }
              }
          } catch (Exception e) {
              e.printStackTrace();
          }
      

      【讨论】:

        猜你喜欢
        • 2014-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-11
        • 1970-01-01
        • 1970-01-01
        • 2020-05-22
        • 1970-01-01
        相关资源
        最近更新 更多