Как указать папку для загрузки файлов Chrome в режиме headless ?

Для хрома в обычном режиме можно добавить опцию и указать папку для файлов которые будут загружатся:

prefs = { “profile.default_content_settings.popups” : 0,
"download.default_directory" : os.getcwd() + “/path_to_folder/” ,
"directory_upgrade" : True }
chrome_options.add_experimental_option( “prefs” , prefs)

Но в режиме headless она не срабатывает. На StackOverflow есть подобные темы, но без решения, а если и написаны, они не рабочие. Кто-то сталкивался с такой проблемой, может есть какой-то хук для решения задачи ?

Есть решение описаное для Ruby, но актуально для любого языка - прокинуть путь через Dev tools protocol 696481 - chromium - An open-source project to help move the web forward. - Monorail

вас не затруднит привести snippet, уже на java , .net или js ?

Перевод c ruby

const { id_ } = await driver.getSession()
const body = {
    "cmd": "Page.setDownloadBehavior",
    "params": {
        "behavior": "allow",
        "downloadPath": "users/blablabla/",
    }
}
await fetch(`http://localhost:4444/wd/hub/session/${id_}/chromium/send_command`, {
    method: 'POST',
    body: JSON.stringify(body),
    headers: { 'Content-Type': 'application/json' }
})
1 лайк

C#:

  if (IsHeadless && BrowserType.ToLower() == "chrome")
            {
                var sessionId = DriverThreadLocal.Value.GetSessionId();
                var cmd2Driver = new CmdToDriver
                {
                    cmd = "Page.setDownloadBehavior",
                    ParamsInfo = new CmdToDriver.Params
                    {
                        behavior = "allow",
                        downloadPath = DowndloadFolder.FullName
                    }
                };
                var json = JsonConvert.SerializeObject(cmd2Driver);
                var port = cds?.Port;
                var url = $"http://localhost:{port}/session/{sessionId}/chromium/send_command";
                var request = new RestRequest(Method.POST);
                request.AddParameter("application/json", json, ParameterType.RequestBody);
                request.AddHeader("Content-Type", "application/json");
                request.RequestFormat = DataFormat.Json;
                ApiManager.SendRequest<object>(url, request);


            }
        }

        public class CmdToDriver
        {
            public string cmd { get; set; }
            [JsonProperty(PropertyName = "params")]
            public Params ParamsInfo {get; set; }

            public class Params
            {
                public string behavior { get; set; }
                public string downloadPath { get; set; }
            }
        }

 public static string GetSessionId(this IWebDriver driver)
        {
            return ((RemoteWebDriver) driver).SessionId.ToString();
        }

сапсибо

пример на офмф:
// based on:
// google chrome - Download files in Java, Selenium using ChromeDriver and headless mode - Stack Overflow

import org.json.JSONException;
import org.json.JSONObject;

private static final String chomeDriverPath =  ...;
	private static final String downloadFilepath = ...;

...
		ChromeDriverService chromeDriverSevice = new ChromeDriverService.Builder()
				.usingDriverExecutable(new File(chomeDriverPath)).usingAnyFreePort()
				.build();
		chromeDriverSevice.start();

		driver = new ChromeDriver(chromeDriverSevice, 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);
		JSONObject commandParamsObj = new JSONObject(commandParams);

		HttpClient httpClient = HttpClientBuilder.create().build();
		String payload = commandParamsObj.toString();

		String u = chromeDriverSevice.getUrl().toString() + "/session/"
				+ driver.getSessionId() + "/chromium/send_command";
		HttpPost request = new HttpPost(u);
		request.addHeader("content-type", "application/json");
		request.setEntity(new StringEntity(payload));
		httpClient.execute(request);

		driver.manage().timeouts().implicitlyWait(4, TimeUnit.SECONDS);
	}


	@Test
	public void testDownload() throws Exception {
		driver.get("http://www.seleniumhq.org/download/");
		driver.findElement(By.linkText("32 bit Windows IE")).click();
	}


А на python кода нету ?)

 def enable_download_in_headless_chrome(br, download_dir):
        # add missing support for chrome "send_command"  to selenium webdriver
        br.command_executor._commands["send_command"] = ("POST", '/session/$sessionId/chromium/send_command')

        params = {'cmd': 'Page.setDownloadBehavior', 'params': {'behavior': 'allow', 'downloadPath': download_dir}}
        command_result = br.execute("send_command", params)
        for key in command_result:
            print("result:" + key + ":" + str(command_result[key]))
        return br

chromeOptions = webdriver.ChromeOptions()
prefs = {'download.default_directory': path_for_downloads, "download.prompt_for_download": False}
chromeOptions.add_experimental_option("prefs", prefs)
if chrome_args != "":
     chromeOptions.add_argument("--headless")
browser = webdriver.Chrome(chrome_driver, chrome_options=chromeOptions)
browser = enable_download_in_headless_chrome(browser, path_for_downloads)

Спасибо !

А есть ли подобная возможность на PHP.

Эти методы для самого селениума, создайте отдельный метод и вызывайте его когда надо .

@Mastaforka А есть ли пример кода на PHP?Или ,возможно, сможете подсказать где посмотреть.
Пока примеров для PHP не нашёл.Буду очень признателен

@Vladislav1 К сожалению не подскажу реализацию на PHP

Благодаря Владу и для PHP и Codeception уже тоже есть. Может пригодиться кому:

$this->executeInSelenium(function (\Facebook\WebDriver\Remote\RemoteWebDriver $webdriver) use (
            $folder
        ) {
            try {
                $command = "Page.setDownloadBehavior";
                $sessionId = $webdriver->getSessionID();
                $body = ['cmd' => $command, 'params' => ['behavior' => 'allow', 'downloadPath' => $folder]];
                // Тут стучимся из контейнера с кодесепшном в контейнер с хромом
                $url = "http://chrome:4444/wd/hub/session/$sessionId/chromium/send_command";
                $this->comment("SessionId: $sessionId");
                $this->comment("Body: " . json_encode($body));
                $this->comment("Url: $url");

                $ch = curl_init();
                curl_setopt($ch, CURLOPT_URL, $url);
                curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
                curl_setopt($ch, CURLOPT_POST, 1);
                curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                $response = curl_exec($ch);
                $this->comment("Response: $response");
                curl_close($ch);
            } catch (Exception $e) {
                $this->comment("Exception MESSAGE ERROR: " . $e . "\n");
            }
        });