web-dev-qa-db-fra.com

Comment puis-je télécharger un fichier sur un événement de clic en utilisant du sélénium?

Je travaille sur python et Selenium. Je veux télécharger le fichier en cliquant sur l'événement en utilisant Selenium. J'ai écrit le code suivant.

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()

Je souhaite télécharger les deux fichiers à partir de liens avec le nom "Exporter les données" à partir de l'URL donnée. Comment puis-je y parvenir car cela fonctionne uniquement avec l'événement Click?

36
sam

Recherchez le lien à l'aide de find_element(s)_by_*, puis appelez la méthode 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()

Ajout d'un code de manipulation de profil pour empêcher la boîte de dialogue de téléchargement.

56
falsetru

J'admets que cette solution est un peu plus "hacky" que l'alternative de Firefox Profile saveToDisk, mais elle fonctionne sur les deux Chrome et Firefox, et ne repose pas sur une fonctionnalité spécifique au navigateur qui pourrait changer à tout moment. Et si rien d'autre, peut-être que cela donnera à quelqu'un une perspective un peu différente sur la façon de résoudre les défis futurs.

Prérequis : Assurez-vous que Selenium et pyvirtualdisplay sont installés ...

  • Python 2: Sudo pip install Selenium pyvirtualdisplay
  • Python 3: Sudo pip3 install Selenium pyvirtualdisplay

La magie

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.

Explication

Nous chargeons d'abord une URL sur le domaine à partir duquel nous ciblons le téléchargement d'un fichier. Cela nous permet d'effectuer une AJAX sur ce domaine, sans rencontrer cross site scripting problèmes.

Ensuite, nous injectons du javascript dans le DOM qui déclenche une demande AJAX. Une fois que la demande AJAX renvoie une réponse, nous prenons la réponse et chargeons dans un objet FileReader. De là, nous pouvons extraire le contenu encodé en base64 du fichier en appelant readAsDataUrl (). Nous prenons ensuite le contenu encodé en base64 et l'ajoutons à window, une variable accessible globalement.

Enfin, parce que la demande AJAX est asynchrone, nous entrons une boucle Python en attendant que le contenu soit ajouté à la fenêtre. Une fois qu'il est ajouté, nous décodons le contenu base64 récupéré de la fenêtre et l'enregistrer dans un fichier.

Cette solution devrait fonctionner sur tous les navigateurs modernes pris en charge par Selenium, et fonctionne que ce soit du texte ou binaire, et sur tous les types MIME.

Approche alternative

Bien que je n'aie pas testé cela, Selenium vous offre la possibilité d'attendre qu'un élément soit présent dans le DOM. Plutôt que de boucler jusqu'à ce qu'une variable accessible globalement soit remplie, vous pouvez créer un élément avec un ID particulier dans le DOM et utiliser la liaison de cet élément comme déclencheur pour récupérer le fichier téléchargé.

11
Joshua Burns

Dans chrome ce que je fais est de télécharger les fichiers en cliquant sur les liens, puis j'ouvre chrome://downloads page, puis récupérez la liste des fichiers téléchargés à partir du DOM fantôme comme ceci:

docs = document
  .querySelector('downloads-manager')
  .shadowRoot.querySelector('#downloads-list')
  .getElementsByTagName('downloads-item')

Cette solution est limitée à Chrome, les données contiennent également des informations telles que le chemin d'accès au fichier et la date de téléchargement. (notez que ce code provient de JS, peut ne pas être la bonne python)

4
TiagoLr

Voici le code de travail complet. Vous pouvez utiliser la mise au rebut Web pour entrer le mot de passe du nom d'utilisateur et un autre champ. Pour obtenir les noms de champ apparaissant sur la page Web, utilisez l'élément inspect. Le nom de l'élément (nom d'utilisateur, mot de passe ou bouton de clic) peut être entré via la classe ou le nom.

from Selenium import webdriver
# Using Chrome to access web
options = webdriver.ChromeOptions() 
options.add_argument("download.default_directory=C:/Test") # Set the download Path
driver = webdriver.Chrome(options=options)
# Open the website
try:
    driver.get('xxxx') # Your Website Address
    password_box = driver.find_element_by_name('password')
    password_box.send_keys('xxxx') #Password
    download_button = driver.find_element_by_class_name('link_w_pass')
    download_button.click()
    driver.quit()
except:
    driver.quit()
    print("Faulty URL")
0
Ashutosh Kumar