Я признаю это решение немного более «взломанным», чем альтернативный вариант Firefox Profile saveToDisk, но он работает как в Chrome, так и в Firefox и не зависит от специфики браузера, которая может измениться в любое время , И если ничего другого, возможно, это даст кому-то немного другой взгляд на то, как решать будущие задачи.
Предпосылки: Убедитесь, что у вас есть селен и 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 в этом домене, без проблем с cross site scripting.
Далее мы вводим некоторый javascript в DOM, который запускает запрос AJAX. Когда запрос AJAX возвращает ответ, мы берем ответ и загружаем его в объект FileReader. Оттуда мы можем извлечь содержимое в кодировке base64 файла, вызвав readAsDataUrl(). Затем мы берем кодированный base64 контент и добавляем его в window
, являющуюся доступной по всему миру переменной.
Наконец, поскольку запрос AJAX является асинхронным, мы вводим цикл Python while, ожидающий добавления содержимого в окно. Когда он добавлен, мы декодируем содержимое base64, извлеченное из окна, и сохраним его в файле.
Это решение должно работать во всех современных браузерах, поддерживаемых Selenium, и работает как текстовые, так и двоичные, а также во всех типах mime.
Альтернативный подход
В то время как я не проверял это, Селен делает себе вам возможность ждать, пока элемент не присутствует в DOM. Вместо того, чтобы заполнять глобально доступную переменную, вы можете создать элемент с определенным идентификатором в DOM и использовать привязку этого элемента в качестве триггера для загрузки загруженного файла.
Я рекомендую использовать 'urllib' и использовать' urllib.urlretrieve (url) 'для загрузки, где' url' - это URL-адрес, который посылает ссылка вы до – Serial
нет, потому что он работает только с событием click. – sam
, но если вы проанализируете HTML-страницу, вы можете получить ссылку, которую посылает событие клика в браузере, и использовать ее – Serial