python - tutorial - ¿Cómo puedo descargar un archivo en un evento de clic usando selenio?
the django project (3)
Admitiré que esta solución es un poco más "hacky" que la alternativa saveToDisk de Firefox Profile, pero funciona tanto en Chrome como en Firefox, y no depende de una función específica del navegador que pueda cambiar en cualquier momento. Y si nada más, tal vez esto le dará a alguien una perspectiva diferente sobre cómo resolver los desafíos del futuro.
Requisitos previos : asegúrese de tener selenio y pyvirtualdisplay instalados ...
- Python 2:
sudo pip install selenium pyvirtualdisplay
- Python 3:
sudo pip3 install selenium pyvirtualdisplay
La magia
import pyvirtualdisplay
import selenium
import selenium.webdriver
import time
import base64
import json
root_url = ''https://www.google.com''
download_url = ''https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png''
print(''Opening virtual display'')
display = pyvirtualdisplay.Display(visible=0, size=(1280, 1024,))
display.start()
print(''/tDone'')
print(''Opening web browser'')
driver = selenium.webdriver.Firefox()
#driver = selenium.webdriver.Chrome() # Alternately, give Chrome a try
print(''/tDone'')
print(''Retrieving initial web page'')
driver.get(root_url)
print(''/tDone'')
print(''Injecting retrieval code into web page'')
driver.execute_script("""
window.file_contents = null;
var xhr = new XMLHttpRequest();
xhr.responseType = ''blob'';
xhr.onload = function() {
var reader = new FileReader();
reader.onloadend = function() {
window.file_contents = reader.result;
};
reader.readAsDataURL(xhr.response);
};
xhr.open(''GET'', %(download_url)s);
xhr.send();
""".replace(''/r/n'', '' '').replace(''/r'', '' '').replace(''/n'', '' '') % {
''download_url'': json.dumps(download_url),
})
print(''Looping until file is retrieved'')
downloaded_file = None
while downloaded_file is None:
# Returns the file retrieved base64 encoded (perfect for downloading binary)
downloaded_file = driver.execute_script(''return (window.file_contents !== null ? window.file_contents.split(/',/')[1] : null);'')
print(downloaded_file)
if not downloaded_file:
print(''/tNot downloaded, waiting...'')
time.sleep(0.5)
print(''/tDone'')
print(''Writing file to disk'')
fp = open(''google-logo.png'', ''wb'')
fp.write(base64.b64decode(downloaded_file))
fp.close()
print(''/tDone'')
driver.close() # close web browser, or it''ll persist after python exits.
display.popen.kill() # close virtual display, or it''ll persist after python exits.
Explicación
Primero cargamos una URL en el dominio al que apuntamos desde la descarga de un archivo. Esto nos permite realizar una solicitud AJAX en ese dominio, sin tener que ejecutar problemas de scripts entre sitios .
A continuación, inyectamos javascript en el DOM que activa una solicitud AJAX. Una vez que la solicitud AJAX devuelve una respuesta, tomamos la respuesta y la cargamos en un objeto FileReader. Desde allí podemos extraer el contenido codificado en base64 del archivo llamando a readAsDataUrl (). Luego tomamos el contenido codificado en base64 y lo agregamos a la window
, una variable accesible a nivel mundial.
Finalmente, debido a que la solicitud AJAX es asincrónica, ingresamos un bucle Python mientras esperamos que el contenido se anexe a la ventana. Una vez que se adjunta, decodificamos el contenido de base64 recuperado de la ventana y lo guardamos en un archivo.
Esta solución debería funcionar en todos los navegadores modernos compatibles con Selenium, y funciona ya sea de texto o binario, y en todos los tipos de mime.
Enfoque alternativo
Si bien no he probado esto, Selenium no le permite esperar hasta que un elemento esté presente en el DOM. En lugar de bucles hasta que se rellena una variable accesible a nivel mundial, puede crear un elemento con un ID particular en el DOM y usar el enlace de ese elemento como desencadenante para recuperar el archivo descargado.
Estoy trabajando en python y selenio. Deseo descargar el archivo del evento de clics con selenio. Escribí el siguiente código.
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.keys import Keys
browser = webdriver.Firefox()
browser.get("http://www.drugcite.com/?q=ACTIMMUNE")
browser.close()
Quiero descargar ambos archivos de enlaces con el nombre "Exportar datos" desde la url dada. ¿Cómo puedo lograrlo ya que funciona solo con el evento click?
En Chrome, lo que hago es descargar los archivos haciendo clic en los enlaces, luego abro chrome://downloads
página de chrome://downloads
y luego recupero la lista de archivos descargados de shadow DOM de la siguiente manera:
docs = document
.querySelector(''downloads-manager'')
.shadowRoot.querySelector(''#downloads-list'')
.getElementsByTagName(''downloads-item'')
Esta solución está restringida a Chrome, los datos también contienen información como la ruta del archivo y la fecha de descarga. (tenga en cuenta que este código es de JS, puede no ser la sintaxis de python correcta)
Encuentra el enlace usando find_element(s)_by_*
, luego llama al método click
.
from selenium import webdriver
# To prevent download dialog
profile = webdriver.FirefoxProfile()
profile.set_preference(''browser.download.folderList'', 2) # custom location
profile.set_preference(''browser.download.manager.showWhenStarting'', False)
profile.set_preference(''browser.download.dir'', ''/tmp'')
profile.set_preference(''browser.helperApps.neverAsk.saveToDisk'', ''text/csv'')
browser = webdriver.Firefox(profile)
browser.get("http://www.drugcite.com/?q=ACTIMMUNE")
browser.find_element_by_id(''exportpt'').click()
browser.find_element_by_id(''exporthlgt'').click()
Se agregó un código de manipulación de perfil para evitar el diálogo de descarga.