Подтвердить что ты не робот

Как я могу загрузить файл по событию клика, используя селен?

Я работаю над питоном и селеном. Я хочу скачать файл из события клика, используя селен. Я написал следующий код.

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

Я хочу скачать оба файла по ссылкам с именем "Экспорт данных" по указанному URL. Как я могу добиться этого, так как он работает только с событием клика?

4b9b3361

Ответ 1

Найдите ссылку, используя find_element(s)_by_*, затем вызовите метод 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()

Добавлен код манипуляции профиля, чтобы предотвратить диалог загрузки.

Ответ 2

Я признаю, что это решение немного более "хакерское", чем альтернатива saveToDisk в профиле Firefox, но оно работает как в Chrome, так и в Firefox и не зависит от функции браузера, которая может измениться в любое время. И если ничего другого, возможно, это даст кому-то немного другой взгляд на то, как решать будущие задачи.

Предварительные условия. Убедитесь, что у вас установлены selenium и pyvirtualdisplay...

  • Python 2: sudo pip install selenium pyvirtualdisplay
  • Python 3: sudo pip3 install selenium pyvirtualdisplay

Магия

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.

Explaination

Сначала мы загружаем URL в домен, для которого мы нацелены на загрузку файла. Это позволяет нам выполнять запрос AJAX в этом домене, не сталкиваясь с межсайтовыми сценариями.

Затем мы вводим некоторый JavaScript в DOM, который запускает AJAX-запрос. Как только AJAX-запрос возвращает ответ, мы берем ответ и загружаем его в объект FileReader. Оттуда мы можем извлечь содержимое файла в кодировке base64, вызвав readAsDataUrl(). Затем мы берем содержимое в кодировке base64 и добавляем его в window, глобально доступную переменную.

Наконец, поскольку AJAX-запрос является асинхронным, мы вводим цикл Python, ожидая добавления содержимого в окно. После добавления мы декодируем содержимое base64, полученное из окна, и сохраняем его в файл.

Это решение должно работать во всех современных браузерах, поддерживаемых Selenium, и работает как с текстовым или двоичным кодом, так и со всеми типами MIME.

Альтернативный подход

Хотя я не проверял это, Selenium предоставляет вам возможность подождать, пока элемент не появится в DOM. Вместо зацикливания, пока не будет заполнена глобально доступная переменная, вы можете создать элемент с определенным идентификатором в DOM и использовать привязку этого элемента в качестве триггера для извлечения загруженного файла.

Ответ 3

В chrome я загружаю файлы, нажимая на ссылки, затем открываю страницу chrome://downloads, а затем извлекаю список загруженных файлов из теневого DOM следующим образом:

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

Это решение ограничено хром, данные также содержат информацию, такую ​​как путь к файлу и дата загрузки. (обратите внимание, что этот код принадлежит JS, может быть не правильным синтаксисом python)

Ответ 4

Вот полный рабочий код. Вы можете использовать веб-утилиту для ввода пароля и другого поля. Для получения имен полей, появляющихся на веб-странице, используйте элемент inspect. Имя элемента (имя пользователя, пароль или кнопка нажатия) можно вводить с помощью класса или имени.

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