在新选项卡中下载时如何在 Selenium (Java) 中无头下载文件?

How to download files headless in Selenium (Java) when download happens in new tab?

我有一个网页,当我单击一个按钮时,它会打开另一个选项卡,然后在其中几秒钟后下载一个 csv 文件。我试图无头地自动执行此操作,但我无法这样做。我正在使用下面的代码。但我认为以下解决方案适用于在同一 window 中进行的下载。我该如何调整它以适应我的情况?

如果我 运行 通过注释掉行 options.addArguments("--headless");

这通常(非无头),代码可以正常工作并且文件可以下载
    System.setProperty("webdriver.chrome.driver", webdriverpath);
    ChromeOptions options = new ChromeOptions();
    options.setExperimentalOption("useAutomationExtension", false);
    options.addArguments("--test-type");
    options.addArguments("--headless");
    options.addArguments("--disable-extensions"); 
    ChromeDriverService driverService = ChromeDriverService.createDefaultService();


    HashMap<String, Object> chromePrefs = new HashMap<String, Object>();
    chromePrefs.put("profile.default_content_settings.popups", 0);
    chromePrefs.put("download.default_directory", downloadFilepath);
    options.setExperimentalOption("prefs", chromePrefs);


    ChromeDriver driver = new ChromeDriver(driverService, options);

    Map<String, Object> commandParams = new HashMap<>();
    commandParams.put("cmd", "Page.setDownloadBehavior");
    Map<String, String> params = new HashMap<>();
    params.put("behavior", "allow");
    params.put("downloadPath", downloadFilepath);
    commandParams.put("params", params);
    ObjectMapper objectMapper = new ObjectMapper();
    HttpClient httpClient = HttpClientBuilder.create().build();
    String command = objectMapper.writeValueAsString(commandParams);
    String u = driverService.getUrl().toString() + "/session/" + driver.getSessionId() + "/chromium/send_command";
    HttpPost request = new HttpPost(u);
    request.addHeader("content-type", "application/json");
    request.setEntity(new StringEntity(command));
    httpClient.execute(request);




    //OPEN URL
    //Click Button

我在无头模式下下载时遇到同样的问题。(但在非无头模式下工作)

我找到了解决方案(Python中的示例):

第一步 - 单击“下载”按钮并切换到新标签页:

download_btn.send_keys(Keys.Control + Keys.RETURN)  //click button to download
print("windows count:", len(self.driver.window_handles)) //check how many windonws(tab)
print("window:", self.driver.current_window_handle)  //check current window
download_btn.send_keys(Keys.Control + "2")  //switch window to new tab
self.driver.switch_to.window(self.driver.window_handles[-1]) // using driver switch to last created tab
print("windows count:", len(self.driver.window_handles))
print("window:", self.driver.current_window_handle)

输出(确认window已成功切换到新标签页):

windows count: 2

window: CDwindow-9D0B0A86678939EE6EA89B4627016F5A

windows count: 2

window: CDwindow-43ACC6E22256C42592CD34E880A08079

第二步 - 配置下载行为agian

您可以将下面的代码包装起来,在切换到新标签页后调用它。

params = {'behavior': 'allow', 'downloadPath': download_path}
print("Change default download dir to :", params['downloadPath'])
driver.execute_cdp_cmd('Page.setDownloadBehavior', params) 

第三步 - 重新加载页面(重要步骤)

它将触发下载行为。

 self.driver.refresh()

这是在 Java 中适用的解决方案:

点击下载按钮后立即切换到新标签页并刷新 :

    ArrayList<String> tabs2 = new ArrayList<String> (driver.getWindowHandles());
    driver.switchTo().window(tabs2.get(1));
    driver.navigate().refresh();

(在我的例子中,它在没有刷新的情况下工作。所以你也可以尝试不使用该语句)