Descargue un archivo a una ruta específica usando Selenium WebDriver

Necesito descargar un archivo a una ubicación determinada en una máquina no local. Este es el flujo normal del navegador web para el que haría esto:

  • Ir al sitio web
  • Haga clic en el botón para descargar el archivo (es un formulario que genera el archivo, no es un enlace de descarga)
  • El sitio web muestra una ventana de alerta “¿Desea descargar este archivo?”, Etc.

Quiero poder omitir el archivo y hacer algo como:

>>> path_to_download_path = PATH >>> button = driver.find_element_by_css("...") >>> button.click() --> And the file is automatically downloaded to my PATH (or wherever I choose) 

¿O hay una forma más fácil de click , donde puedo descargar automáticamente el contenido del archivo?

¿Cómo haría esto?

Tendría que examinar el javascript en el sitio web y entender cómo funciona antes de anularlo para hacer algo así, pero incluso así, la seguridad del navegador siempre abrirá un cuadro de diálogo que le pedirá que confirme la descarga. Eso te deja con dos opciones (por lo que puedo ver):

  • Confirmar el diálogo de alerta
  • Determine la ubicación del archivo en el servidor remoto y use un GET para descargar el archivo

Realmente no puedo ayudar con los detalles, ya que no sé python, pero espero que eso ayude …

Use Selenium Webdriver

Usa el perfil de Firefox para descargar tus archivos. Este perfil salta ese cuadro de diálogo de firefox. En línea:-

  pro.setPreference("browser.downLoad.folderList", 0); 

El valor de browser.download.folderList se puede establecer en 0, 1 o 2. Cuando se establece en 0, Firefox guardará todos los archivos descargados a través del navegador en el escritorio del usuario. Cuando se establece en 1, estas descargas se almacenan en la carpeta Descargas. Cuando se establece en 2, la ubicación especificada para la descarga más reciente se utiliza de nuevo.

Código de perfil de Firefox que necesitas implementar: –

  FirefoxProfile pro=new FirefoxProfile(); pro.setPreference("browser.downLoad.folderList", 0); pro.setPreference("browser.helperApps.neverAsk.saveToDisk", "Applications/zip"); WebDriver driver=new FirefoxDriver(pro); driver.get("http://selenium-release.storage.googleapis.com/2.47/selenium-java-2.47.1.zip"); 

Espero que te ayude 🙂

Cuando inicie su controlador, asegúrese de establecer las preferencias de descarga.

Para Firefox:

 ff_prof.set_preference( "browser.download.manager.showWhenStarting", False ) ff_prof.set_preference( "browser.download.folderList", 2 ) ff_prof.set_preference( "browser.download.useDownloadDir", True ) ff_prof.set_preference( "browser.download.dir", self.driver_settings['download_folder'] ) ## # if FF still shows the download dialog, make sure that the filetype is included below # filetype string options can be found in '~/.mozilla/$USER_PROFILE/mimeTypes.rdf' ## mime_types = ("application/pdf", "text/html") ff_prof.set_preference( "browser.helperApps.neverAsk.saveToDisk", (", ".join( mime_types )) ) ff_prof.set_preference( "browser.helperApps.neverAsk.openFile", (", ".join( mime_types )) ) 

Para Chrome:

 capabilities['chromeOptions']['prefs']['download.prompt_for_download'] = False capabilities['chromeOptions']['prefs']['download.default_directory'] = self.driver_settings['download_folder'] 

Reenviando la descarga:

A continuación se muestra el código que uso para redirigir el archivo desde self.driver_settings['download_folder'] (establecido arriba) a donde realmente desea que el archivo ( to_path puede ser una carpeta existente o una ruta de archivo). Si está en Linux, sugeriría usar tmpfs para que /tmp se mantenga en la memoria RAM y luego establezca self.driver_settings['download_folder'] en "/tmp/driver_downloads/" . Tenga en cuenta que la siguiente función supone que self.driver_settings['download_folder'] siempre comienza como una carpeta vacía (así es como localiza el archivo que se está descargando, ya que es el único en el directorio).

 def moveDriverDownload(self, to_path, allowable_extensions, allow_rename_if_exists=False, timeout_seconds=None): if timeout_seconds is None: timeout_seconds = 30 wait_delta = timedelta( seconds=timeout_seconds ) start_download_time = datetime.now() hasTimedOut = lambda: datetime.now() - start_download_time > wait_delta assert isinstance(allowable_extensions, list) or isinstance(allowable_extensions, tuple) or isinstance(allowable_extensions, set), "instead of a list, found allowable_extensions type of '{}'".format(type(allowable_extensions)) allowable_extensions = [ elem.lower().strip() for elem in allowable_extensions ] allowable_extensions = [ elem if elem.startswith(".") else "."+elem for elem in allowable_extensions ] if not ".part" in allowable_extensions: allowable_extensions.append( ".part" ) re_extension_str = "(?:" + ("$)|(?:".join( re.escape(elem) for elem in allowable_extensions )) + "$)" getFiles = lambda: next( os.walk( self.driver_settings['download_folder'] ) )[2] while True: if hasTimedOut(): del allowable_extensions[ allowable_extensions.index(".part") ] raise DownloadTimeoutError( "timed out after {} seconds while waiting on file download with extension in {}".format(timeout_seconds, allowable_extensions) ) time.sleep( 0.5 ) file_list = [ elem for elem in getFiles() if re.search( re_extension_str, elem ) ] if len(file_list) > 0: break file_list = [ re.search( r"(?i)^(.*?)(?:\.part)?$", elem ).groups()[0] for elem in file_list ] if len(file_list) > 1: if len(file_list) == 2: if file_list[0] != file_list[1]: raise Exception( "file_list[0] != file_list[1] <==> {} != {}".format(file_list[0], file_list[1]) ) else: raise Exception( "len(file_list) > 1. found {}".format(file_list) ) file_path = "%s%s" %(self.driver_settings['download_folder'], file_list[0]) # see if the file is still being downloaded by checking if it's open by any programs if platform.system() == "Linux": openProcess = lambda: subprocess.Popen( 'lsof | grep "%s"' %file_path, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE ) fileIsFinished = lambda txt: txt.strip() == "" elif platform.system() == "Windows": # 'handle' program must be in PATH # https://technet.microsoft.com/en-us/sysinternals/bb896655 openProcess = lambda: subprocess.Popen( 'handle "%s"' %file_path.replace("/", "\\"), shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE ) fileIsFinished = lambda txt: bool( re.search("(?i)No matching handles found", txt) ) else: raise Exception( "unrecognised platform.system() of '{}'".format(platform.system()) ) while True: lsof_process = openProcess() lsof_result = lsof_process.communicate() if len(lsof_result) != 2: raise Exception( "len(lsof_result) != 2. found {}".format(lsof_result) ) if lsof_result[1].strip() != "": raise Exception( 'lsof_result[1].strip() != "". found {}'.format(lsof_result) ) if fileIsFinished( lsof_result[0] ): break if hasTimedOut(): raise Exception( "timed out after {} seconds waiting for '{}' to be freed from writing. found lsof/handle of '{}'".format(timeout_seconds, file_path, lsof_result[0]) ) time.sleep( 0.5 ) to_path = to_path.replace("\\", "/") if os.path.isdir( to_path ): if not to_path.endswith("/"): to_path += "/" to_path += file_list[0] i = 2 while os.path.exists( to_path ): if not allow_rename_if_exists: raise Exception( "{} already exists".format(to_path) ) to_path = re.sub( "^(.*/)(.*?)(?:-" + str(i-1) + r")?(|\..*?)?$", r"\1\2-%i\3" %i, to_path ) i += 1 shutil.move( file_path, to_path ) return to_path[ to_path.rindex("/")+1: ]