Descargando con Chrome Headless y Selenium
Estoy usando python-selenium y Chrome 59 e intento automatizar una secuencia de descarga simple. Cuando inicio el navegador normalmente, la descarga funciona, pero cuando lo hago en modo sin cabeza, la descarga no funciona.
# 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
Incluso intenté agregar una ruta predeterminada:
prefs = {"download.default_directory" : "/Users/Chetan/Desktop/"}
chromeOptions.add_argument("headless")
chromeOptions.add_experimental_option("prefs",prefs)
Agregar una ruta predeterminada funciona en la implementación normal, pero el mismo problema persiste en la versión sin cabeza.
¿Cómo hago para que la descarga comience en modo sin cabeza?
Sí, es una "característica" de seguridad. Como se mencionó anteriormente, aquí está la discusión sobre el error: https://bugs.chromium.org/p/chromium/issues/detail?id=696481
Se agregó soporte en la versión 62.0.3196.0 de Chrome o superior para permitir la descarga.
Aquí hay una implementación de Python. Tuve que agregar el comando a los comandos de Chromedriver. Intentaré enviar un PR para que se incluya en la biblioteca en el futuro.
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)
Como referencia, aquí hay un pequeño repositorio para demostrar cómo usar esto: https://github.com/shawnbutton/PythonHeadlessChrome
actualización 2020-05-01 Ha habido comentarios que dicen que esto ya no funciona. Dado que este parche tiene más de un año, es muy posible que hayan cambiado la biblioteca subyacente.
Los desarrolladores de Chromium agregaron recientemente un segundo modo sin cabeza (en 2021). Consulte https://bugs.chromium.org/p/chromium/issues/detail?id=706008#c36
Posteriormente cambiaron el nombre de la opción en 2023 para Chrome 109 -> https://github.com/chromium/chromium/commit/e9c516118e2e1923757ecb13e6d9fff36775d1f4
Para Chrome 109 y superiores, la --headless=new
bandera ahora le permitirá obtener la funcionalidad completa de Chrome en el nuevo modo sin cabeza, e incluso podrá ejecutar extensiones en él. (Para las versiones de Chrome 96 a 108, utilice --headless=chrome
)
Uso: (Chrome 109 y superior):
options.add_argument("--headless=new")
Uso: (Chrome 96 a Chrome 108):
options.add_argument("--headless=chrome")
Si algo funciona en Chrome normal, ahora también debería funcionar con el modo sin cabeza más nuevo.