web-dev-qa-db-fra.com

Téléchargement avec chrome sans tête et sélénium

J'utilise python-Selenium et Chrome 59 et j'essaie d'automatiser une séquence de téléchargement simple. Lorsque je lance le navigateur normalement, le téléchargement fonctionne, mais lorsque je le fais en mode sans tête, le téléchargement ne fonctionne pas.

# Headless implementation
from Selenium import webdriver

chromeOptions = webdriver.ChromeOptions()
chromeOptions.add_argument("headless")

driver = webdriver.Chrome(chrome_options=chromeOptions)

driver.get('https://www.mockaroo.com/')
driver.find_element_by_id('download').click()
# ^^^ Download doesn't start

# Normal Mode
from Selenium import webdriver

driver = webdriver.Chrome()

driver.get('https://www.mockaroo.com/')
driver.find_element_by_id('download').click()
# ^^^ Download works normally

J'ai même essayé d'ajouter un chemin par défaut:

prefs = {"download.default_directory" : "/Users/Chetan/Desktop/"}
chromeOptions.add_argument("headless")
chromeOptions.add_experimental_option("prefs",prefs)

L'ajout d'un chemin par défaut fonctionne dans l'implémentation normale, mais le même problème persiste dans la version sans tête.

Comment faire pour que le téléchargement démarre en mode sans tête?

30
TheChetan

Oui, c'est une "fonctionnalité", pour la sécurité. Comme mentionné précédemment, voici la discussion sur le bogue: https://bugs.chromium.org/p/chromium/issues/detail?id=696481

Le support a été ajouté dans la version chrome 62.0.3196.0 ou supérieure pour permettre le téléchargement.

Voici une implémentation en python. Je devais ajouter la commande aux commandes chromedriver. Je vais essayer de soumettre un PR afin qu'il soit inclus dans la bibliothèque à l'avenir. 

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

    params = {'cmd': 'Page.setDownloadBehavior', 'params': {'behavior': 'allow', 'downloadPath': download_dir}}
    command_result = driver.execute("send_command", params)

Pour référence, voici un petit rapport expliquant comment utiliser ceci: https://github.com/shawnbutton/PythonHeadlessChrome

33
Shawn Button

Cette fonctionnalité de Chrome empêche les logiciels de télécharger des fichiers sur votre ordinateur. Il existe cependant une solution de contournement. En savoir plus à ce sujet ici .

Ce que vous devez faire, c'est l'activer via DevTools, quelque chose comme ça:

async function setDownload () {
  const client = await CDP({tab: 'ws://localhost:9222/devtools/browser'});
  const info =  await client.send('Browser.setDownloadBehavior', {behavior : "allow", downloadPath: "/tmp/"});
  await client.close();
}

C'est la solution que quelqu'un a donnée dans le sujet mentionné. Voici son commentaire .

15
Some1Else

Voici un exemple de travail pour Python basé sur la réponse de Shawn Button . J'ai testé cela avec Chromium 68.0.3440.75 & chromedriver 2.38

from Selenium import webdriver
from Selenium.webdriver.chrome.options import Options

chrome_options = Options()
chrome_options.add_experimental_option("prefs", {
  "download.default_directory": "/path/to/download/dir",
  "download.Prompt_for_download": False,
})

chrome_options.add_argument("--headless")
driver = webdriver.Chrome(chrome_options=chrome_options)

driver.command_executor._commands["send_command"] = ("POST", '/session/$sessionId/chromium/send_command')
params = {'cmd': 'Page.setDownloadBehavior', 'params': {'behavior': 'allow', 'downloadPath': "/path/to/download/dir"}}
command_result = driver.execute("send_command", params)

driver.get('http://download-page.url/')
driver.find_element_by_css_selector("#download_link").click()
5
Fayçal

Peut-être que le site Web que vous gérez renvoie différentes pages HTML pour les navigateurs, cela signifie le XPath ou l'Id que vous voulez peut-être différemment dans un navigateur sans en-tête ... Essayez de télécharger pageSource dans un navigateur sans en-tête et ouvrez-le en tant que page HTML vous voulez . Vous pouvez voir cela comme c # exemple Comment cacher FirefoxDriver (avec Selenium) sans erreur de fonction findElement dans PhantomDriver?

3
Hazem

En général, il est redondant de voir la même chose simplement écrite dans une autre langue, mais comme ce problème m'a rendu fou, j'espère que je sauve quelqu'un d'autre de la douleur ... alors voici la version C # de Réponse de Shawn Button (testé avec chrome sans tête = 71.0.3578.98, chromedriver = 2.45.615279, plate-forme = Linux 4.9.125-linuxkit x86_64)):

            var enableDownloadCommandParameters = new Dictionary<string, object>
            {
                { "behavior", "allow" },
                { "downloadPath", downloadDirectoryPath }
            };
            var result = ((OpenQA.Selenium.Chrome.ChromeDriver)driver).ExecuteChromeCommandWithResult("Page.setDownloadBehavior", enableDownloadCommandParameters);
1
victorvartan

Un exemple complet d'utilisation de JavaScript avec Selenium-cucumber-js/Selenium-webdriver:

const chromedriver = require('chromedriver');
const Selenium = require('Selenium-webdriver');
const command = require('Selenium-webdriver/lib/command');
const chrome = require('Selenium-webdriver/chrome');

module.exports = function() {

  const chromeOptions = new chrome.Options()
    .addArguments('--no-sandbox', '--headless', '--start-maximized', '--ignore-certificate-errors')
    .setUserPreferences({
      'profile.default_content_settings.popups': 0, // disable download file dialog
      'download.default_directory': '/tmp/downloads', // default file download location
      "download.Prompt_for_download": false,
      'download.directory_upgrade': true,
      'safebrowsing.enabled': false,
      'plugins.always_open_pdf_externally': true,
      'plugins.plugins_disabled': ["Chrome PDF Viewer"]
    })
    .windowSize({width: 1600, height: 1200});

  const driver = new Selenium.Builder()
    .withCapabilities({
      browserName: 'chrome',
      javascriptEnabled: true,
      acceptSslCerts: true,
      path: chromedriver.path
    })
    .setChromeOptions(chromeOptions)
    .build();

  driver.manage().window().maximize();

  driver.getSession()
    .then(session => {
      const cmd = new command.Command("SEND_COMMAND")
        .setParameter("cmd", "Page.setDownloadBehavior")
        .setParameter("params", {'behavior': 'allow', 'downloadPath': '/tmp/downloads'});
      driver.getExecutor().defineCommand("SEND_COMMAND", "POST", `/session/${session.getId()}/chromium/send_command`);
      return driver.execute(cmd);
    });

  return driver;
};

La partie clé est:

  driver.getSession()
    .then(session => {
      const cmd = new command.Command("SEND_COMMAND")
        .setParameter("cmd", "Page.setDownloadBehavior")
        .setParameter("params", {'behavior': 'allow', 'downloadPath': '/tmp/downloads'});
      driver.getExecutor().defineCommand("SEND_COMMAND", "POST", `/session/${session.getId()}/chromium/send_command`);
      return driver.execute(cmd);
    });

Testé avec:

  • Chrome 67.0.3396.99
  • Chromedriver 2.36.540469
  • Sélénium-concombre-js 1.5.12
  • Sélénium-webdriver 3.0.0
0
Mykhailo Kovalskyi

Voici l'équivalent en Java, Selenium, chromedriver et chrome v 71.x. Le code entrant est la clé permettant d’enregistrer les téléchargements Fichiers JAR supplémentaires: com.fasterxml.jackson.core, com.fasterxml.jackson.annotation, com.fasterxml.jackson.databind.

System.setProperty ("webdriver.chrome.driver", "C:\libraries\chromedriver.exe");

            String downloadFilepath = "C:\\Download";
            HashMap<String, Object> chromePreferences = new HashMap<String, Object>();
            chromePreferences.put("profile.default_content_settings.popups", 0);
            chromePreferences.put("download.Prompt_for_download", "false");
            chromePreferences.put("download.default_directory", downloadFilepath);
            ChromeOptions chromeOptions = new ChromeOptions();
            chromeOptions.setBinary("C:\\pathto\\Chrome SxS\\Application\\chrome.exe");

            //ChromeOptions options = new ChromeOptions();
            //chromeOptions.setExperimentalOption("prefs", chromePreferences);
            chromeOptions.addArguments("start-maximized");
            chromeOptions.addArguments("disable-infobars");


            //HEADLESS CHROME
            **chromeOptions.addArguments("headless");**

            chromeOptions.setExperimentalOption("prefs", chromePreferences);
            DesiredCapabilities cap = DesiredCapabilities.chrome();
            cap.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
            cap.setCapability(ChromeOptions.CAPABILITY, chromeOptions);

            **ChromeDriverService driverService = ChromeDriverService.createDefaultService();
            ChromeDriver driver = new ChromeDriver(driverService, chromeOptions);

            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));**
            try {
                httpClient.execute(request);
            } catch (IOException e2) {
                // TODO Auto-generated catch block
                e2.printStackTrace();
            }**

        //Continue using the driver for automation  
    driver.manage().window().maximize();
0
Manasi Vora

J'ai résolu ce problème en utilisant la solution de contournement partagée par @Shawn Button et en utilisant le chemin complet pour le paramètre 'downloadPath'. L'utilisation d'un chemin relatif n'a pas fonctionné et m'a donné l'erreur.

Versions:
Chrome Version 75.0.3770.100 (version officielle) (32 bits)
ChromeDriver 75.0.3770.90

0
Matheus Araujo