kshnkvn
@kshnkvn
yay ✌️ t.me/kshnkvn

КМП, или можете, пожалуйста, объяснить как устроены параметры Selenium webdriver?

Лезу в официальную документацию, смотрю как инициализировать webdriver, делаю:
from selenium import webdriver

driver = webdriver.Firefox(firefox_profile='D:\\Develop\\redirect_watotg\\profile.default',
                           executable_path='D:\\Develop\\redirect_watotg\\Lib\\geckodriver.exe')
print(driver.firefox_profile.path)
driver.get('https://web.whatsapp.com/')

Запускаю - работает. Чудеса! Смотрю вывод:
>>> C:\Users\kshnk\AppData\Local\Temp\tmp_mkfpnfj\webdriver-py-profilecopy

Смотрю в ту папку, которую я указал - пустая. Прохожу авторизацию на сайте, закрываю браузер, запускаю заново - нет авторизации. Другого и не ожидал, но все-же.
Лезу в гугл, нахожу ответ в репозитории selenium:
def __init__(self, profile_directory=None):
        """
        Initialises a new instance of a Firefox Profile
        :args:
         - profile_directory: Directory of profile that you want to use. If a
           directory is passed in it will be cloned and the cloned directory
           will be used by the driver when instantiated.
           This defaults to None and will create a new
           directory when object is created.
        """

Понял, с этим все окей. То-есть то, что я указал в атрибуте firefox_profile указывает на то, какой каталог должен использоваться как основа, но сам он задействован не будет, соответственно если он пустой изначально, то он таким и останется, Selenium не будет из временной папки возвращать данные обратно в указанную мною папку (а может есть решение, но я его не нашел). Ищу как поступить. Нашел на сайте mozilla. Попробовал:
from selenium import webdriver
from selenium.webdriver.firefox.options import Options

driver_options = Options()
driver_options.add_argument('-profile')
driver_options.add_argument('D:\\Develop\\redirect_watotg\\profile.default')

driver = webdriver.Firefox(options=driver_options,
                           executable_path='D:\\Develop\\redirect_watotg\\Lib\\geckodriver.exe',
                           service_args=["--marionette-port", "2828"])
print(driver.firefox_profile.path)

Строка print(driver.firefox_profile.path) больше не со мной:
Traceback (most recent call last):
File "D:/Develop/redirect_watotg/main.py", line 22, in
print(driver.firefox_profile.path)
AttributeError: 'NoneType' object has no attribute 'path'

Ну и ладно, удаляю её, запускаю снова - запустилось, смотрю в указанною папку - браузер туда положил все свои рабочие файлы, авторизовываюсь, закрываю браузер, запускаю повторно - авторизация на месте. Супер!
Следующие этап - мне нужен headless режим. Нахожу на все том-же (почти) сайте mozilla, добавляю всего одну строчку:
driver_options.add_argument('-headless')
Проверяю - работает. Все еще супер. Следующее - нужно сделать так, что-бы не загружались css (в идеале) и была возможность скачивать видео-файлы, т.к. на данный момент при нажатии на загрузку вылазит окно с вариантом сохранения, или открытия. Нахожу решение для отключения css и для включения возможности загрузки. Так-же глядя на код вспоминаю о print(driver.firefox_profile.path) и возвращаю его на место, убираю headless, что-бы посмотреть на результат. Итоговый вариант кода:
from selenium import webdriver
from selenium.webdriver.firefox.options import Options, FirefoxProfile


driver_options, driver_profile = Options(), FirefoxProfile()
# driver_options.add_argument('-headless')
driver_options.add_argument('-profile')
driver_options.add_argument('D:\\Develop\\redirect_watotg\\profile.default')
driver_profile.set_preference('permissions.default.stylesheet', 2)
driver_profile.set_preference('browser.download.folderList', 2)
driver_profile.set_preference('browser.download.manager.showWhenStarting', False)
driver_profile.set_preference('browser.download.dir', 'D:\\Develop\\redirect_watotg\\Downloads')
driver_profile.set_preference("browser.download.manager.closeWhenDone", False)
driver_profile.set_preference("browser.download.manager.focusWhenStarting", False)
driver_profile.set_preference('browser.helperApps.neverAsk.saveToDisk', "video/mp4")

driver = webdriver.Firefox(options=driver_options, firefox_profile=driver_profile,
                           executable_path='D:\\Develop\\redirect_watotg\\Lib\\geckodriver.exe',
                           service_args=["--marionette-port", "2828"])

print(driver.firefox_profile.path)
driver.get('https://web.whatsapp.com/')

Запускаю - все css на месте, при попытке загрузки вылазит окно с предложением открыть/сохранить MP4 Video File (VLC). Пока скрипт не останавливаю, иду в папку C:\Users\kshnk\AppData\Local\Temp\tmp_4shdr7q , о которой мне любезно рассказал print(), замечаю, что там всего только один файл, хотя по-идеи туда должны были скопироваться все файлы из указанной мною директории, при этом файл, который там есть (user.js) отсутствует в моей директории. Открываю его, вижу очень много строчек с разными параметрами, а среди них есть и указанные мною:
user_pref("permissions.default.stylesheet", 2);
user_pref("browser.download.folderList", 2);
user_pref("browser.download.manager.showWhenStarting", false);
user_pref("browser.download.dir", "D:\\Develop\\redirect_watotg\\Downloads");
user_pref("browser.download.manager.closeWhenDone", false);
user_pref("browser.download.manager.focusWhenStarting", false);
user_pref("browser.helperApps.neverAsk.saveToDisk", "video/mp4");

Смотрю на ссылку - выглядит странно, меняю на относительный 'Downloads', перезапускаю скрипт - результат тот-же.
На этом моменте я всё, больше ничего не нашел.
Пожалуйста, подскажите в каком моменте (кроме того, когда я решил пытаться в программирование - он очевиден) из всех вышеперечисленных мною я совершил ошибку и неверно интерпретировал найденные мною данные. Как итог у меня два вопроса:
1. Почему не копируются файлы во временную папку (хотя я не думаю, что это критично, но все-же так должно быть)?
2. Почему не работают set_preference()?
3. Чисто бонусом, если вдруг решение прошлых будет найдено - можно-ли проверить статус загрузки, или его название встроенными возможностями selenium, без отсебятины?

Всем спасибо, кто осилил это прочитать и огромное спасибо тем, кто решится помочь.

UPD
В строку
driver_profile.set_preference('browser.helperApps.neverAsk.saveToDisk', "video/mp4")

Добавил все существующие mime-типы - не помогло.

UPD 2
Изучил инспектор кода в Firefox, вкладку сеть - увидел, что при нажатии кнопки "Загрузить" ничего не появляется, но именно при загрузке фрейма с видео есть какой-то application/octet-stream, больше особо ничего, включая video/mp4. Решил добавить его - ничего, решил оставить только его - тоже ничего. Заметил, что при появлении окна открыть/загрузить в источнике "из" указано blob: Может в этом дело? Пошел дальше в гугл.

UPD 3
Так-так-так, методом тыка пришел к выводу, что ломает всю картину все параметры driver_options.add_argument(), убрал из инициализации options=driver_options и вуаля - заработали driver_profile.set_preference(), правда от идеи отключить CSS пришлось отказаться - сайт полностью ломается и скрипт с ним больше работать не может, но настроить загрузку удалось.
Но! Теперь вернулся к своей первоначальной проблеме - как указать директорию профиля, что-бы можно было сохранять сессию, ведь изначально эта директория добавлялась как раз таки функцией driver_options.add_argument().

UPD 4
Так, похоже лажа именно с driver_options.add_argument('-profile') - сам по себе он работает, но из-за него не работает ни один set_preference(), в то время как driver_options.add_argument('-headless') отлично со всеми дружит. Но вскрылась еще беда с set_preference('browser.download.dir', 'sdsadasd') - она не работает. Как вы можете заметить в качестве параметра крайне странный адрес, но функции плевать, что туда не напиши - она загружает все файлы в папку загрузки установленную по умолчанию.
Как итог - все еще актуальна проблема с созданием первоначального профиля и не рабочий параметр указания папки загрузки. В принципе вопрос решаем - тот-же профиль можно тупо после выполнения функции авторизации скопировать в нужную мне папку, а потом подгружать параметром FirefoxProfile('D:/Develop/redirect_watotg/profile.default') - такой вариант работает. Тоже самое можно сделать и с файлов загрузки, только нужно узнать под каким названием он загружается и когда именно он загрузился. Но все-же хотелось-бы разобраться с тем, что дает selenium.
P.S. Аномально огромная активность сегодня на тостере. И да, это уже больше похоже на блог, но я все еще надеюсь, что мне кто-то поможет.

UPD 5
Что-же, мой план провалился на корню - написал я значит две заветные строчки, которые должны были решить мою проблему с сохранением авторизации:
shutil.rmtree('D:/Develop/redirect_watotg/Profile')
shutil.copytree(profile_path, 'D:/Develop/redirect_watotg/Profile/')

Пока не увидел, что после авторизации у меня в папке "Profile" всего один файл - user.js и вспомнил начало истории: указывая папку профиля в FirefoxProfile() произойдет копирование файлов из папки профиля, а указанием папки и последующим созданием в ней файлов профиля занимался driver_options.add_argument(), который в моем случае не работает.
  • Вопрос задан
  • 555 просмотров
Решения вопроса 1
kshnkvn
@kshnkvn Автор вопроса
yay ✌️ t.me/kshnkvn
Итого нашел временные меры:
1. Для сохранения сессии копирую каталог, но т.к. некоторые файлы заняты процессом пришлось оборачивать блоков try-except. Хорошо, что именно файлы отвечающие за сохранение сессии успевают скопироваться, хотя в целом решение так себе:
path_file = open('D:/Develop/redirect_watotg/geckodriver.log')
matches = []
for line in path_file:
    if line.count('rust_mozprofile'):
        matches.append(line)
profile_path = 'C:/Users/kshnk/AppData/Local/Temp/' + matches[-1].split('\"')[-2].split('\\')[-1]
print(profile_path)
shutil.rmtree('D:/Develop/redirect_watotg/Profile')
try:
    shutil.copytree(profile_path, 'D:/Develop/redirect_watotg/Profile/')
except shutil.Error as e:
    print(e)

2. С именем скачанного файла чуть проще:
Перед вызовом функции загрузки файла:
before = os.listdir('D:/Downloads')
И после того, как функция завершила работу:
after = os.listdir('D:/Downloads')
difference = set(after) - set(before)
if len(difference) == 1:
    file_name = difference.pop()
    print(file_name)
    return file_name
else:
    return False


Надеюсь со временем найду более правильные решения, если будет актуально.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы